Initial commit (no patches)

This commit is contained in:
Elliot Nunn 2019-04-03 00:12:47 +08:00
commit 69cecde571
4 changed files with 188 additions and 0 deletions

71
bin/deepen Executable file
View File

@ -0,0 +1,71 @@
#!/usr/bin/env python3
import argparse
from os import path, makedirs, walk, listdir, remove
from shutil import copy, rmtree
from subprocess import run
def folder(default_search, user_input):
if path.sep in user_input:
return user_input
else:
the_path = path.dirname(path.dirname(path.abspath(__file__)))
the_path = path.join(the_path, default_search, user_input)
return the_path
parser = argparse.ArgumentParser(description='''
Expand a patchset into a git repository (based on git-am)
''')
parser.add_argument('patchset', metavar='PATCHSET', action='store', type=lambda x: folder('patchset', x), help='Patchset (assumed in ../patchset/)')
parser.add_argument('worktree', metavar='WORKTREE', action='store', type=lambda x: folder('worktree', x), help='Destination worktree (assumed in ../worktree/)')
group = parser.add_mutually_exclusive_group()
group.add_argument('--base', metavar='SRC', action='store', default='SuperMarioProj.1994-02-09', type=lambda x: folder('base', x), help='Base source tree (default=SuperMarioProj.1994-02-09, assumed in ../base/)')
group.add_argument('--base-commit', metavar='REV', action='store', help='Base commit')
parser.add_argument('--branch', metavar='BRANCH', action='store', default='master', help='Destination branch')
args = parser.parse_args()
assert path.exists(args.patchset)
assert not path.exists(path.join(args.patchset, '.git')) # protect against argument swap
makedirs(args.worktree, exist_ok=True)
run(['git', 'init'], cwd=args.worktree, check=True)
run(['git', 'checkout', '--orphan', args.branch], cwd=args.worktree, check=True)
# This cleans the working directory, because the manpage's suggestion `git rm -rf .` does not work
run(['git', 'reset'], cwd=args.worktree, check=True)
for do_delete in listdir(args.worktree):
if do_delete != '.git':
do_delete = path.join(args.worktree, do_delete)
try:
rmtree(do_delete)
except NotADirectoryError:
remove(do_delete)
if args.base_commit is not None:
run(['git', 'reset', '--hard', args.base_commit], cwd=args.worktree, check=True)
else:
for walk_base, walk_dirs, walk_files in walk(args.base):
walk_dirs[:] = [x for x in walk_dirs if not x.startswith('.')]
walk_files[:] = [x for x in walk_files if not x.startswith('.')]
other_dir = path.join(args.worktree, path.relpath(walk_base, args.base))
makedirs(other_dir, exist_ok=True)
for this_file in walk_files:
copy(path.join(walk_base, this_file), other_dir)
run(['git', 'add', '.'], cwd=args.worktree, check=True)
run(['git', 'commit', '-m', path.basename(args.base)], cwd=args.worktree, check=True)
run(['git', 'tag', args.branch+'-patchset-base'], cwd=args.worktree, check=True)
patchfiles = [path.join(args.patchset, x) for x in sorted(listdir(args.patchset)) if path.splitext(x)[1].lower() == '.patch']
run(['git', 'am', *patchfiles], cwd=args.worktree, check=True)

42
bin/flatten Executable file
View File

@ -0,0 +1,42 @@
#!/usr/bin/env python3
import argparse
from os import path, getcwd, makedirs, listdir, remove
from subprocess import run
def folder(default_search, user_input):
if path.sep in user_input:
return user_input
else:
the_path = path.dirname(path.dirname(path.abspath(__file__)))
the_path = path.join(the_path, default_search, user_input)
return the_path
parser = argparse.ArgumentParser(description='''
Shrink a git changelog into a patchset (based on git format-patch)
''')
parser.add_argument('worktree', metavar='WORKTREE', nargs='?', action='store', default=getcwd(), type=lambda x: folder('worktree', x), help='Worktree (default is cwd, or assumed in ../worktree/)')
parser.add_argument('patchset', metavar='PATCHSET', action='store', type=lambda x: folder('patchset', x), help='Destination patchset (assumed in ../patchset/)')
args = parser.parse_args()
args.patchset = path.abspath(args.patchset)
assert not path.exists(path.join(args.patchset, '.git')) # protect against argument swap
assert path.exists(path.join(args.worktree, '.git'))
makedirs(args.patchset, exist_ok=True)
for do_delete in listdir(args.patchset):
do_delete = path.join(args.patchset, do_delete)
if path.splitext(do_delete)[1].lower() == '.patch':
remove(do_delete)
run(['git', 'format-patch', '-o', args.patchset, '--anchored=;', 'master-patchset-base..HEAD'], cwd=args.worktree, check=True)

54
bin/getsrc Executable file
View File

@ -0,0 +1,54 @@
#!/usr/bin/env python3
import argparse
from os import path, makedirs
from shutil import rmtree
def folder(default_search, user_input):
if path.sep in user_input:
return user_input
else:
the_path = path.dirname(path.dirname(path.abspath(__file__)))
the_path = path.join(the_path, default_search, user_input)
return the_path
parser = argparse.ArgumentParser(description='''
Extract an "original" source code tree from an HFS disk image, or
(on macOS) a folder. If a destination is given that does not contain
a path separator, it will created as a subdirectory of ../base/
''')
parser.add_argument('src', metavar='SOURCE', action='store', help='Disk image, archive, folder, whatever')
parser.add_argument('--out', '-o', metavar='DEST', action='store', default='SuperMarioProj.1994-02-09', type=lambda x: folder('base', x), help='Processed source tree (default=SuperMarioProj.1994-02-09)')
args = parser.parse_args()
if path.splitext(args.src)[1].lower() in ('.dmg', '.img', '.dsk'):
from machfs import Volume
with open(args.src, 'rb') as f:
v = Volume()
v.read(f.read())
# slight hack: remove nonprinting chars from text files
for parent, child_dirnames, child_filenames in v.walk():
for c in child_filenames:
o = v[parent + (c,)]
if o.type == b'TEXT':
nudata = bytes(b for b in o.data if b >= 32 or b == 9 or b == 13)
if nudata != o.data:
print(parent + (c,), len(o.data), len(nudata))
o.data = nudata
try:
rmtree(args.out)
except FileNotFoundError:
pass
makedirs(args.out, exist_ok=True)
v.write_folder(args.out)
else:
raise NotImplementedError()

21
readme.md Normal file
View File

@ -0,0 +1,21 @@
# Introduction
The SuperMario sources (passed around as "System 7.1") are interesting
reading, but they cannot be built as-is. This project aims to produce
several modifications to SuperMarioProj ("patchsets") that can be
applied to the code and compiled into something useful.
You will need the SuperMarioProj sources to get started. These are not
hosted here, but a script is provided to import them from an HFS disk
image: `bin/getsrc System7.1.dmg`.
# Patching
Two Python scripts are provided to help use and modify the patchsets:
`bin/deepen` and `bin/flatten`. The first converts a folder of `.patch`
files to a branch in a git repository, and the second does the opposite.
Detailed help is available by running each with the `-h` switch.
# Building
To build the sources, check out BuildCubeE (soon to be renamed).