mirror of
https://github.com/ihaveamac/custom-install.git
synced 2026-03-09 09:52:00 +00:00
Compare commits
3 Commits
f81734f293
...
safe-insta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5cf735e55f | ||
|
|
6a79b6ca86 | ||
|
|
46361111ba |
32
.github/workflows/build-finalize.yml
vendored
Normal file
32
.github/workflows/build-finalize.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Build finalize (3DS)
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- 'finalize/**'
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- 'finalize/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: devkitpro/devkitarm:20260219
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Build finalize module
|
||||||
|
working-directory: finalize
|
||||||
|
run: make
|
||||||
|
|
||||||
|
- name: Upload build artifacts
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: finalize-3dsx
|
||||||
|
path: |
|
||||||
|
finalize/custom-install-finalize.3dsx
|
||||||
|
finalize/custom-install-finalize.elf
|
||||||
|
finalize/custom-install-finalize.smdh
|
||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -2,7 +2,6 @@
|
|||||||
bin/linux/save3ds_fuse
|
bin/linux/save3ds_fuse
|
||||||
cstins/
|
cstins/
|
||||||
testing-class.py
|
testing-class.py
|
||||||
*.local
|
|
||||||
|
|
||||||
# macOS
|
# macOS
|
||||||
.DS_Store
|
.DS_Store
|
||||||
@@ -12,16 +11,12 @@ testing-class.py
|
|||||||
venv/
|
venv/
|
||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
*.pyc
|
*.pyc
|
||||||
*.egg-info/
|
|
||||||
*.whl
|
|
||||||
|
|
||||||
# JetBrains
|
# JetBrains
|
||||||
.idea/
|
.idea/
|
||||||
=======
|
=======
|
||||||
|
|
||||||
|
*.pyc
|
||||||
/build/
|
/build/
|
||||||
/dist/
|
/dist/
|
||||||
/custom-install-finalize.3dsx
|
/custom-install-finalize.3dsx
|
||||||
|
|
||||||
result
|
|
||||||
result-*
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2019 Ian Burgwin
|
Copyright (c) 2019-2021 Ian Burgwin
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
recursive-include custominstall/bin/*
|
|
||||||
include custominstall/title.db.gz
|
|
||||||
include custominstall/TaskbarLib.tlb
|
|
||||||
include custominstall/custom-install-finalize.3dsx
|
|
||||||
51
README.md
51
README.md
@@ -12,28 +12,19 @@ Installs a title directly to an SD card for the Nintendo 3DS. Originally created
|
|||||||
3. Extract and run ci-gui. Read `windows-quickstart.txt`.
|
3. Extract and run ci-gui. Read `windows-quickstart.txt`.
|
||||||
|
|
||||||
### With installed Python
|
### With installed Python
|
||||||
|
Note for Windows users: Enabling "Add Python 3.X to PATH" is **NOT** required! Python is installed with the `py` launcher by default.
|
||||||
> [!NOTE]
|
|
||||||
> Windows users: Enabling "Add Python 3.X to PATH" is **NOT** required! Python is installed with the `py` launcher by default.
|
|
||||||
|
|
||||||
1. [Dump boot9.bin and movable.sed](https://ihaveamac.github.io/dump.html) from a 3DS system.
|
1. [Dump boot9.bin and movable.sed](https://ihaveamac.github.io/dump.html) from a 3DS system.
|
||||||
2. Install the packages:
|
2. Download the repo ([zip link](https://github.com/ihaveamac/custom-install/archive/safe-install.zip) or `git clone`)
|
||||||
* Windows: `py -3 -m pip install --user --upgrade https://github.com/ihaveamac/custom-install/archive/refs/heads/python-package.zip`
|
3. Install the packages:
|
||||||
* macOS/Linux: `python3 -m pip install --user --upgrade https://github.com/ihaveamac/custom-install/archive/refs/heads/python-package.zip`
|
* Windows: Double-click `windows-install-dependencies.py`
|
||||||
|
* Alternate manual method: `py -3 -m pip install --user -r requirements-win32.txt`
|
||||||
To run the GUI:
|
* macOS/Linux: `python3 -m pip install --user -r requirements.txt`
|
||||||
* Windows: `py -3 -m custominstall.gui`
|
4. Run `custominstall.py` with boot9.bin, movable.sed, path to the SD root, and CIA files to install (see Usage section).
|
||||||
* macOS/Linux: `python3 -m custominstall.gui`
|
5. Download and use [custom-install-finalize](https://github.com/ihaveamac/custom-install/releases) on the 3DS system to finish the install.
|
||||||
|
|
||||||
To run the command line version:
|
|
||||||
* Windows: `py -3 -m custominstall`
|
|
||||||
* macOS/Linux: `python3 -m custominstall`
|
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
Linux users must build [wwylele/save3ds](https://github.com/wwylele/save3ds) and place `save3ds_fuse` in one of these places:
|
Linux users must build [wwylele/save3ds](https://github.com/wwylele/save3ds) and place `save3ds_fuse` in `bin/linux`. Install [rust using rustup](https://www.rust-lang.org/tools/install), then compile with: `cargo build --release --no-default-features`. The compiled binary is located in `target/release/save3ds_fuse`, copy it to `bin/linux`.
|
||||||
* A directory in `PATH`
|
|
||||||
* In `custominstall/bin/linux`
|
|
||||||
* Set the environment variable `CUSTOM_INSTALL_SAVE3DS_PATH` to the `save3ds_fuse` binary
|
|
||||||
|
|
||||||
movable.sed is required and can be provided with `-m` or `--movable`.
|
movable.sed is required and can be provided with `-m` or `--movable`.
|
||||||
|
|
||||||
@@ -64,9 +55,9 @@ Use `-h` to view arguments.
|
|||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
```
|
```
|
||||||
py -3 -m custominstall -b boot9.bin -m movable.sed --sd E:\ file.cia file2.cia
|
py -3 custominstall.py -b boot9.bin -m movable.sed --sd E:\ file.cia file2.cia
|
||||||
python3 -m custominstall -b boot9.bin -m movable.sed --sd /Volumes/GM9SD file.cia file2.cia
|
python3 custominstall.py -b boot9.bin -m movable.sed --sd /Volumes/GM9SD file.cia file2.cia
|
||||||
python3 -m custominstall -b boot9.bin -m movable.sed --sd /media/GM9SD file.cia file2.cia
|
python3 custominstall.py -b boot9.bin -m movable.sed --sd /media/GM9SD file.cia file2.cia
|
||||||
```
|
```
|
||||||
|
|
||||||
## GUI
|
## GUI
|
||||||
@@ -75,14 +66,26 @@ A GUI is provided to make the process easier.
|
|||||||
### GUI Setup
|
### GUI Setup
|
||||||
Linux users may need to install a Tk package:
|
Linux users may need to install a Tk package:
|
||||||
- Ubuntu/Debian: `sudo apt install python3-tk`
|
- Ubuntu/Debian: `sudo apt install python3-tk`
|
||||||
- Arch: `sudo pacman -S tk`
|
- Manjaro/Arch: `sudo pacman -S tk`
|
||||||
|
|
||||||
|
Install the requirements listed in "Summary", then run `ci-gui.py`.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
### Building Windows standalone
|
### Building Windows standalone
|
||||||
|
|
||||||
> [!WARNING]
|
Using a 32-bit version of Python is recommended to build a version to be distributed.
|
||||||
> This section is OUTDATED and currently does not work with the Python package setup.
|
|
||||||
|
A [virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/#creating-a-virtual-environment) is recommended to isolate the packages from system directories. The build script `make-standalone.bat` assumes that the dependencies are in PATH.
|
||||||
|
|
||||||
|
Install the dependencies, plus cx-Freeze. In a virtual environment, the specific Python version doesn't need to be requested.
|
||||||
|
```batch
|
||||||
|
pip install cx-freeze -r requirements-win32.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
Copy `custom-install-finalize.3dsx` to the project root, this will be copied to the build directory and included in the final archive.
|
||||||
|
|
||||||
|
Run `make-standalone.bat`. This will run cxfreeze and make a standalone version at `dist\custom-install-standalone.zip`
|
||||||
|
|
||||||
## License/Credits
|
## License/Credits
|
||||||
[save3ds by wwylele](https://github.com/wwylele/save3ds) is used to interact with the Title Database (details in `bin/README`).
|
[save3ds by wwylele](https://github.com/wwylele/save3ds) is used to interact with the Title Database (details in `bin/README`).
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# This file is a part of custom-install.py.
|
# This file is a part of custom-install.py.
|
||||||
#
|
#
|
||||||
# custom-install is copyright (c) 2019 Ian Burgwin
|
# custom-install is copyright (c) 2019-2020 Ian Burgwin
|
||||||
# This file is licensed under The MIT License (MIT).
|
# This file is licensed under The MIT License (MIT).
|
||||||
# You can find the full license text in LICENSE.md in the root of this project.
|
# You can find the full license text in LICENSE.md in the root of this project.
|
||||||
|
|
||||||
@@ -25,8 +25,7 @@ from pyctr.type.cdn import CDNError
|
|||||||
from pyctr.type.cia import CIAError
|
from pyctr.type.cia import CIAError
|
||||||
from pyctr.type.tmd import TitleMetadataError
|
from pyctr.type.tmd import TitleMetadataError
|
||||||
|
|
||||||
from . import __version__
|
from custominstall import CustomInstall, CI_VERSION, load_cifinish, InvalidCIFinishError, InstallStatus
|
||||||
from .__main__ import CustomInstall, load_cifinish, InvalidCIFinishError, InstallStatus, save3ds_fuse_path
|
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from os import PathLike
|
from os import PathLike
|
||||||
@@ -230,12 +229,8 @@ class InstallResults(tk.Toplevel):
|
|||||||
else:
|
else:
|
||||||
message = 'Nothing was installed.'
|
message = 'Nothing was installed.'
|
||||||
|
|
||||||
if install_state['installed']:
|
if install_state['installed'] and copied_3dsx:
|
||||||
if copied_3dsx:
|
|
||||||
message += '\n\ncustom-install-finalize has been copied to the SD card.'
|
message += '\n\ncustom-install-finalize has been copied to the SD card.'
|
||||||
else:
|
|
||||||
message += ('\n\nNote: custom-install-finalize was not copied.\n'
|
|
||||||
'You can either manually copy the 3dsx to your SD card, or use GodMode9 to finish the install.')
|
|
||||||
|
|
||||||
if application_count >= 300:
|
if application_count >= 300:
|
||||||
message += (f'\n\nWarning: {application_count} installed applications were detected.\n'
|
message += (f'\n\nWarning: {application_count} installed applications were detected.\n'
|
||||||
@@ -340,9 +335,7 @@ class CustomInstallGUI(ttk.Frame):
|
|||||||
self.file_picker_textboxes['sd'] = sd_selected
|
self.file_picker_textboxes['sd'] = sd_selected
|
||||||
|
|
||||||
def auto_input_filename(self, f, filename):
|
def auto_input_filename(self, f, filename):
|
||||||
sd_msed_path = find_first_file(
|
sd_msed_path = find_first_file([join(f, 'gm9', 'out', filename), join(f, filename)])
|
||||||
[join(f, "gm9", "out", filename), join(f, "boot9strap", filename), join(f, filename)]
|
|
||||||
)
|
|
||||||
if sd_msed_path:
|
if sd_msed_path:
|
||||||
self.log('Found ' + filename + ' on SD card at ' + sd_msed_path)
|
self.log('Found ' + filename + ' on SD card at ' + sd_msed_path)
|
||||||
if filename.endswith('bin'):
|
if filename.endswith('bin'):
|
||||||
@@ -504,7 +497,7 @@ class CustomInstallGUI(ttk.Frame):
|
|||||||
self.status_label = ttk.Label(self, text='Waiting...')
|
self.status_label = ttk.Label(self, text='Waiting...')
|
||||||
self.status_label.grid(row=5, column=0, sticky=tk.NSEW)
|
self.status_label.grid(row=5, column=0, sticky=tk.NSEW)
|
||||||
|
|
||||||
self.log(f'custom-install {__version__} - https://github.com/ihaveamac/custom-install', status=False)
|
self.log(f'custom-install {CI_VERSION} - https://github.com/ihaveamac/custom-install', status=False)
|
||||||
|
|
||||||
if is_windows and not taskbar:
|
if is_windows and not taskbar:
|
||||||
self.log('Note: Could not load taskbar lib.')
|
self.log('Note: Could not load taskbar lib.')
|
||||||
@@ -605,8 +598,6 @@ class CustomInstallGUI(ttk.Frame):
|
|||||||
if status:
|
if status:
|
||||||
self.status_label.config(text=line)
|
self.status_label.config(text=line)
|
||||||
|
|
||||||
print(log_msg)
|
|
||||||
|
|
||||||
def show_error(self, message):
|
def show_error(self, message):
|
||||||
mb.showerror('Error', message, parent=self.parent)
|
mb.showerror('Error', message, parent=self.parent)
|
||||||
|
|
||||||
@@ -744,17 +735,8 @@ class CustomInstallGUI(ttk.Frame):
|
|||||||
Thread(target=install).start()
|
Thread(target=install).start()
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
if not (save3ds_fuse_path and isfile(save3ds_fuse_path)):
|
|
||||||
mb.showerror('Error', "Couldn't find save3ds_fuse. Please place it PATH.")
|
|
||||||
return
|
|
||||||
|
|
||||||
window = tk.Tk()
|
window = tk.Tk()
|
||||||
window.title(f'custom-install {__version__}')
|
window.title(f'custom-install {CI_VERSION}')
|
||||||
frame = CustomInstallGUI(window)
|
frame = CustomInstallGUI(window)
|
||||||
frame.pack(fill=tk.BOTH, expand=True)
|
frame.pack(fill=tk.BOTH, expand=True)
|
||||||
window.mainloop()
|
window.mainloop()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
# This file is a part of custom-install.py.
|
# This file is a part of custom-install.py.
|
||||||
#
|
#
|
||||||
# custom-install is copyright (c) 2019 Ian Burgwin
|
# custom-install is copyright (c) 2019-2020 Ian Burgwin
|
||||||
# This file is licensed under The MIT License (MIT).
|
# This file is licensed under The MIT License (MIT).
|
||||||
# You can find the full license text in LICENSE.md in the root of this project.
|
# You can find the full license text in LICENSE.md in the root of this project.
|
||||||
|
|
||||||
@@ -10,12 +10,12 @@ from argparse import ArgumentParser
|
|||||||
from enum import Enum
|
from enum import Enum
|
||||||
from glob import glob
|
from glob import glob
|
||||||
import gzip
|
import gzip
|
||||||
from os import makedirs, rename, scandir, environ
|
from os import makedirs, rename, scandir
|
||||||
from os.path import dirname, join, isdir, isfile
|
from os.path import dirname, join, isdir, isfile
|
||||||
from random import randint
|
from random import randint
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from shutil import copyfile, copy2, rmtree, which
|
from shutil import copyfile, copy2, rmtree
|
||||||
import sys
|
import sys
|
||||||
from sys import platform, executable
|
from sys import platform, executable
|
||||||
from tempfile import TemporaryDirectory
|
from tempfile import TemporaryDirectory
|
||||||
@@ -36,8 +36,6 @@ from pyctr.type.ncch import NCCHSection
|
|||||||
from pyctr.type.tmd import TitleMetadataError
|
from pyctr.type.tmd import TitleMetadataError
|
||||||
from pyctr.util import roundup
|
from pyctr.util import roundup
|
||||||
|
|
||||||
from . import __version__
|
|
||||||
|
|
||||||
if platform == 'msys':
|
if platform == 'msys':
|
||||||
platform = 'win32'
|
platform = 'win32'
|
||||||
|
|
||||||
@@ -48,28 +46,16 @@ if is_windows:
|
|||||||
else:
|
else:
|
||||||
from os import statvfs
|
from os import statvfs
|
||||||
|
|
||||||
script_dir: str
|
CI_VERSION = '2.1'
|
||||||
|
|
||||||
|
# used to run the save3ds_fuse binary next to the script
|
||||||
frozen = getattr(sys, 'frozen', False)
|
frozen = getattr(sys, 'frozen', False)
|
||||||
|
script_dir: str
|
||||||
if frozen:
|
if frozen:
|
||||||
script_dir = dirname(executable)
|
script_dir = dirname(executable)
|
||||||
else:
|
else:
|
||||||
script_dir = dirname(__file__)
|
script_dir = dirname(__file__)
|
||||||
|
|
||||||
# used to run the save3ds_fuse binary next to the script
|
|
||||||
if 'CUSTOM_INSTALL_SAVE3DS_PATH' in environ:
|
|
||||||
save3ds_fuse_path = environ['CUSTOM_INSTALL_SAVE3DS_PATH']
|
|
||||||
else:
|
|
||||||
save3ds_fuse_name = 'save3ds_fuse'
|
|
||||||
if is_windows:
|
|
||||||
save3ds_fuse_name += '.exe'
|
|
||||||
if frozen:
|
|
||||||
save3ds_fuse_path = join(script_dir, 'bin', save3ds_fuse_name)
|
|
||||||
else:
|
|
||||||
save3ds_fuse_path = join(script_dir, 'bin', platform, save3ds_fuse_name)
|
|
||||||
|
|
||||||
if not isfile(save3ds_fuse_path):
|
|
||||||
save3ds_fuse_path = which('save3ds_fuse')
|
|
||||||
|
|
||||||
# missing contents are replaced with 0xFFFFFFFF in the cmd file
|
# missing contents are replaced with 0xFFFFFFFF in the cmd file
|
||||||
CMD_MISSING = b'\xff\xff\xff\xff'
|
CMD_MISSING = b'\xff\xff\xff\xff'
|
||||||
|
|
||||||
@@ -295,7 +281,13 @@ class CustomInstall:
|
|||||||
return isdir(sd_path)
|
return isdir(sd_path)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
if not (save3ds_fuse_path and isfile(save3ds_fuse_path)):
|
if frozen:
|
||||||
|
save3ds_fuse_path = join(script_dir, 'bin', 'save3ds_fuse')
|
||||||
|
else:
|
||||||
|
save3ds_fuse_path = join(script_dir, 'bin', platform, 'save3ds_fuse')
|
||||||
|
if is_windows:
|
||||||
|
save3ds_fuse_path += '.exe'
|
||||||
|
if not isfile(save3ds_fuse_path):
|
||||||
self.log("Couldn't find " + save3ds_fuse_path, 2)
|
self.log("Couldn't find " + save3ds_fuse_path, 2)
|
||||||
return None, False, 0
|
return None, False, 0
|
||||||
|
|
||||||
@@ -700,7 +692,7 @@ class CustomInstall:
|
|||||||
return msg_with_type
|
return msg_with_type
|
||||||
|
|
||||||
|
|
||||||
def main():
|
if __name__ == "__main__":
|
||||||
parser = ArgumentParser(description='Install a CIA to the SD card for a Nintendo 3DS system.')
|
parser = ArgumentParser(description='Install a CIA to the SD card for a Nintendo 3DS system.')
|
||||||
parser.add_argument('cia', help='CIA files', nargs='+')
|
parser.add_argument('cia', help='CIA files', nargs='+')
|
||||||
parser.add_argument('-m', '--movable', help='movable.sed file', required=True)
|
parser.add_argument('-m', '--movable', help='movable.sed file', required=True)
|
||||||
@@ -711,7 +703,7 @@ def main():
|
|||||||
parser.add_argument('--overwrite-saves', help='overwrite existing save files', action='store_true')
|
parser.add_argument('--overwrite-saves', help='overwrite existing save files', action='store_true')
|
||||||
parser.add_argument('--cifinish-out', help='path for cifinish.bin file, defaults to (SD root)/cifinish.bin')
|
parser.add_argument('--cifinish-out', help='path for cifinish.bin file, defaults to (SD root)/cifinish.bin')
|
||||||
|
|
||||||
print(f'custom-install {__version__} - https://github.com/ihaveamac/custom-install')
|
print(f'custom-install {CI_VERSION} - https://github.com/ihaveamac/custom-install')
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
installer = CustomInstall(boot9=args.boot9,
|
installer = CustomInstall(boot9=args.boot9,
|
||||||
@@ -759,7 +751,3 @@ def main():
|
|||||||
installer.log(f'\n\nWarning: {application_count} installed applications were detected.\n'
|
installer.log(f'\n\nWarning: {application_count} installed applications were detected.\n'
|
||||||
f'The HOME Menu will only show 300 icons.\n'
|
f'The HOME Menu will only show 300 icons.\n'
|
||||||
f'Some applications (not updates or DLC) will need to be deleted.')
|
f'Some applications (not updates or DLC) will need to be deleted.')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
# This file is a part of custom-install.
|
|
||||||
#
|
|
||||||
# Copyright (c) 2019 Ian Burgwin
|
|
||||||
# This file is licensed under The MIT License (MIT).
|
|
||||||
# You can find the full license text in LICENSE.md in the root of this project.
|
|
||||||
|
|
||||||
__author__ = 'ihaveahax'
|
|
||||||
__copyright__ = 'Copyright (c) 2019 Ian Burgwin'
|
|
||||||
__license__ = 'MIT'
|
|
||||||
__version__ = '2.1'
|
|
||||||
Binary file not shown.
34
default.nix
34
default.nix
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
pkgs ? import <nixpkgs> { },
|
|
||||||
# just so i can use the same pinned version as the flake...
|
|
||||||
pyctr ? (
|
|
||||||
let
|
|
||||||
flakeLock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
|
||||||
pyctr-repo = import (builtins.fetchTarball (
|
|
||||||
with flakeLock.nodes.pyctr.locked;
|
|
||||||
{
|
|
||||||
url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz";
|
|
||||||
}
|
|
||||||
)) { inherit pkgs; };
|
|
||||||
in
|
|
||||||
pyctr-repo.pyctr
|
|
||||||
),
|
|
||||||
save3ds ? (
|
|
||||||
let
|
|
||||||
flakeLock = builtins.fromJSON (builtins.readFile ./flake.lock);
|
|
||||||
hax-nur-repo = import (builtins.fetchTarball (
|
|
||||||
with flakeLock.nodes.hax-nur.locked;
|
|
||||||
{
|
|
||||||
url = "https://github.com/${owner}/${repo}/archive/${rev}.tar.gz";
|
|
||||||
}
|
|
||||||
)) { inherit pkgs; };
|
|
||||||
in
|
|
||||||
hax-nur-repo.save3ds
|
|
||||||
),
|
|
||||||
}:
|
|
||||||
|
|
||||||
rec {
|
|
||||||
custominstall = pkgs.python3Packages.callPackage ./package.nix {
|
|
||||||
inherit pyctr save3ds;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
82
finalize/flake.lock
generated
82
finalize/flake.lock
generated
@@ -1,82 +0,0 @@
|
|||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"devkitNix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1766539742,
|
|
||||||
"narHash": "sha256-F6OeM2LrLo2n+Xg5XU4udQR/vuWWrDMKxXRzNXE2ClQ=",
|
|
||||||
"owner": "bandithedoge",
|
|
||||||
"repo": "devkitNix",
|
|
||||||
"rev": "c97f9880737716085e78009cba6bf85ad104628b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "bandithedoge",
|
|
||||||
"repo": "devkitNix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1731533236,
|
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1768032153,
|
|
||||||
"narHash": "sha256-6kD1MdY9fsE6FgSwdnx29hdH2UcBKs3/+JJleMShuJg=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "3146c6aa9995e7351a398e17470e15305e6e18ff",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"devkitNix": "devkitNix",
|
|
||||||
"nixpkgs": "nixpkgs"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
||||||
devkitNix.url = "github:bandithedoge/devkitNix";
|
|
||||||
devkitNix.inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = { self, nixpkgs, devkitNix }: let
|
|
||||||
pkgs = import nixpkgs { system = "x86_64-linux"; overlays = [ devkitNix.overlays.default ]; };
|
|
||||||
in {
|
|
||||||
devShells.x86_64-linux = rec {
|
|
||||||
custom-install-finalize = pkgs.mkShell.override { stdenv = pkgs.devkitNix.stdenvARM; } {};
|
|
||||||
cif = custom-install-finalize;
|
|
||||||
default = custom-install-finalize;
|
|
||||||
};
|
|
||||||
|
|
||||||
packages.x86_64-linux = rec {
|
|
||||||
custom-install-finalize = pkgs.devkitNix.stdenvARM.mkDerivation rec {
|
|
||||||
name = "custom-install-finalize";
|
|
||||||
src = builtins.path { path = ./.; name = name; };
|
|
||||||
|
|
||||||
makeFlags = [ "TARGET=${name}" ];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
mkdir $out
|
|
||||||
cp ${name}.3dsx $out
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
cif = custom-install-finalize;
|
|
||||||
default = custom-install-finalize;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -294,11 +294,11 @@ void finalize_install(void)
|
|||||||
|
|
||||||
ticket_buf.title_id_be = __builtin_bswap64(entries[i].title_id);
|
ticket_buf.title_id_be = __builtin_bswap64(entries[i].title_id);
|
||||||
|
|
||||||
res = AM_InstallTicketBegin(&ticketHandle);
|
res = AMNET_InstallTicketBegin(&ticketHandle);
|
||||||
if (R_FAILED(res))
|
if (R_FAILED(res))
|
||||||
{
|
{
|
||||||
printf("Failed to begin ticket install: %08lx\n", res);
|
printf("Failed to begin ticket install: %08lx\n", res);
|
||||||
AM_InstallTicketAbort(ticketHandle);
|
AMNET_InstallTicketAbort(ticketHandle);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,15 +306,15 @@ void finalize_install(void)
|
|||||||
if (R_FAILED(res))
|
if (R_FAILED(res))
|
||||||
{
|
{
|
||||||
printf("Failed to write ticket: %08lx\n", res);
|
printf("Failed to write ticket: %08lx\n", res);
|
||||||
AM_InstallTicketAbort(ticketHandle);
|
AMNET_InstallTicketAbort(ticketHandle);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = AM_InstallTicketFinish(ticketHandle);
|
res = AMNET_InstallTicketFinish(ticketHandle);
|
||||||
if (R_FAILED(res))
|
if (R_FAILED(res))
|
||||||
{
|
{
|
||||||
printf("Failed to finish ticket install: %08lx\n", res);
|
printf("Failed to finish ticket install: %08lx\n", res);
|
||||||
AM_InstallTicketAbort(ticketHandle);
|
AMNET_InstallTicketAbort(ticketHandle);
|
||||||
goto exit;
|
goto exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
167
flake.lock
generated
167
flake.lock
generated
@@ -1,167 +0,0 @@
|
|||||||
{
|
|
||||||
"nodes": {
|
|
||||||
"devkitNix": {
|
|
||||||
"inputs": {
|
|
||||||
"flake-utils": "flake-utils",
|
|
||||||
"nixpkgs": [
|
|
||||||
"finalize",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1766539742,
|
|
||||||
"narHash": "sha256-F6OeM2LrLo2n+Xg5XU4udQR/vuWWrDMKxXRzNXE2ClQ=",
|
|
||||||
"owner": "bandithedoge",
|
|
||||||
"repo": "devkitNix",
|
|
||||||
"rev": "c97f9880737716085e78009cba6bf85ad104628b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "bandithedoge",
|
|
||||||
"repo": "devkitNix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"finalize": {
|
|
||||||
"inputs": {
|
|
||||||
"devkitNix": "devkitNix",
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1,
|
|
||||||
"narHash": "sha256-BZgu7+/RV9Gy1xo/icz5kd2fKCa3Zow+Zz6MJWzpgMM=",
|
|
||||||
"path": "finalize",
|
|
||||||
"type": "path"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"path": "finalize",
|
|
||||||
"type": "path"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"flake-utils": {
|
|
||||||
"inputs": {
|
|
||||||
"systems": "systems"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1731533236,
|
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "flake-utils",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"hax-nur": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
],
|
|
||||||
"treefmt-nix": "treefmt-nix"
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1768151313,
|
|
||||||
"narHash": "sha256-qcMLsdACTlFHltziBAsS1r09cVZyp5fUR16//mIhLIs=",
|
|
||||||
"owner": "ihaveamac",
|
|
||||||
"repo": "nur-packages",
|
|
||||||
"rev": "8ebcd637fd5cd8e673c8e01ed408bf206f9d4f9b",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "ihaveamac",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "nur-packages",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1768032153,
|
|
||||||
"narHash": "sha256-6kD1MdY9fsE6FgSwdnx29hdH2UcBKs3/+JJleMShuJg=",
|
|
||||||
"owner": "NixOS",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "3146c6aa9995e7351a398e17470e15305e6e18ff",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "NixOS",
|
|
||||||
"ref": "nixpkgs-unstable",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"pyctr": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1763515957,
|
|
||||||
"narHash": "sha256-S0qzooGQN5tkbIVgijVZ9umvBC1dYbdPN97tks5SbwE=",
|
|
||||||
"owner": "ihaveamac",
|
|
||||||
"repo": "pyctr",
|
|
||||||
"rev": "eb8d4d06ce7339727d3f72b40f45ec3260336058",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "ihaveamac",
|
|
||||||
"ref": "master",
|
|
||||||
"repo": "pyctr",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": {
|
|
||||||
"inputs": {
|
|
||||||
"finalize": "finalize",
|
|
||||||
"hax-nur": "hax-nur",
|
|
||||||
"nixpkgs": "nixpkgs",
|
|
||||||
"pyctr": "pyctr"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1681028828,
|
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"treefmt-nix": {
|
|
||||||
"inputs": {
|
|
||||||
"nixpkgs": [
|
|
||||||
"hax-nur",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1768031762,
|
|
||||||
"narHash": "sha256-b2gJDJfi+TbA7Hu2sKip+1mWqya0GJaWrrXQjpbOVTU=",
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "treefmt-nix",
|
|
||||||
"rev": "0c445aa21b01fd1d4bb58927f7b268568af87b20",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "numtide",
|
|
||||||
"repo": "treefmt-nix",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"root": "root",
|
|
||||||
"version": 7
|
|
||||||
}
|
|
||||||
80
flake.nix
80
flake.nix
@@ -1,80 +0,0 @@
|
|||||||
{
|
|
||||||
description = "custominstall";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
|
||||||
pyctr.url = "github:ihaveamac/pyctr/master";
|
|
||||||
pyctr.inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
hax-nur.url = "github:ihaveamac/nur-packages/master";
|
|
||||||
hax-nur.inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
finalize.url = "path:finalize";
|
|
||||||
finalize.inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs =
|
|
||||||
inputs@{
|
|
||||||
self,
|
|
||||||
nixpkgs,
|
|
||||||
pyctr,
|
|
||||||
hax-nur,
|
|
||||||
finalize,
|
|
||||||
}:
|
|
||||||
let
|
|
||||||
systems = [
|
|
||||||
"x86_64-linux"
|
|
||||||
"i686-linux"
|
|
||||||
"x86_64-darwin"
|
|
||||||
"aarch64-darwin"
|
|
||||||
"aarch64-linux"
|
|
||||||
"armv6l-linux"
|
|
||||||
"armv7l-linux"
|
|
||||||
];
|
|
||||||
forAllSystems = f: nixpkgs.lib.genAttrs systems (system: f system);
|
|
||||||
in
|
|
||||||
{
|
|
||||||
legacyPackages = forAllSystems (
|
|
||||||
system:
|
|
||||||
(import ./default.nix {
|
|
||||||
pkgs = import nixpkgs { inherit system; };
|
|
||||||
pyctr = pyctr.packages.${system}.pyctr;
|
|
||||||
save3ds = hax-nur.packages.${system}.save3ds;
|
|
||||||
})
|
|
||||||
// {
|
|
||||||
default = self.legacyPackages.${system}.custominstall;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
packages = forAllSystems (
|
|
||||||
system: nixpkgs.lib.filterAttrs (_: v: nixpkgs.lib.isDerivation v) self.legacyPackages.${system}
|
|
||||||
);
|
|
||||||
|
|
||||||
apps = forAllSystems (
|
|
||||||
system:
|
|
||||||
let
|
|
||||||
pkgs = import nixpkgs { inherit system; };
|
|
||||||
in
|
|
||||||
{
|
|
||||||
gui = {
|
|
||||||
type = "app";
|
|
||||||
program = "${self.packages.${system}.custominstall}/bin/custominstall-gui";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// (
|
|
||||||
if system == "x86_64-linux" then
|
|
||||||
# this only works on x86_64-linux due to devkitNix only working there
|
|
||||||
{
|
|
||||||
update-finalize = {
|
|
||||||
type = "app";
|
|
||||||
program =
|
|
||||||
(pkgs.writeShellScript "update-finalize" ''
|
|
||||||
set -x
|
|
||||||
finalize=${inputs.finalize.packages.${system}.custom-install-finalize}/custom-install-finalize.3dsx
|
|
||||||
cp --no-preserve=mode,ownership,timestamps $finalize custominstall/custom-install-finalize.3dsx
|
|
||||||
'').outPath;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{ }
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
13
make-standalone.bat
Normal file
13
make-standalone.bat
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
mkdir build
|
||||||
|
mkdir dist
|
||||||
|
python setup-cxfreeze.py build_exe --build-exe=build\custom-install-standalone
|
||||||
|
mkdir build\custom-install-standalone\bin
|
||||||
|
copy TaskbarLib.tlb build\custom-install-standalone
|
||||||
|
copy bin\win32\save3ds_fuse.exe build\custom-install-standalone\bin
|
||||||
|
copy bin\README build\custom-install-standalone\bin
|
||||||
|
copy custom-install-finalize.3dsx build\custom-install-standalone
|
||||||
|
copy title.db.gz build\custom-install-standalone
|
||||||
|
copy extras\windows-quickstart.txt build\custom-install-standalone
|
||||||
|
copy extras\run_with_cmd.bat build\custom-install-standalone
|
||||||
|
copy LICENSE.md build\custom-install-standalone
|
||||||
|
python -m zipfile -c dist\custom-install-standalone.zip build\custom-install-standalone
|
||||||
74
package.nix
74
package.nix
@@ -1,74 +0,0 @@
|
|||||||
{
|
|
||||||
lib,
|
|
||||||
pkgs,
|
|
||||||
python,
|
|
||||||
callPackage,
|
|
||||||
buildPythonApplication,
|
|
||||||
fetchPypi,
|
|
||||||
pyctr,
|
|
||||||
pycryptodomex,
|
|
||||||
pypng,
|
|
||||||
tkinter,
|
|
||||||
setuptools,
|
|
||||||
events,
|
|
||||||
stdenv,
|
|
||||||
save3ds,
|
|
||||||
|
|
||||||
withGUI ? true,
|
|
||||||
}:
|
|
||||||
|
|
||||||
let
|
|
||||||
save3ds_no_fuse = save3ds.override { withFUSE = false; };
|
|
||||||
in
|
|
||||||
buildPythonApplication rec {
|
|
||||||
pname = "custominstall";
|
|
||||||
version = "2.1";
|
|
||||||
pyproject = true;
|
|
||||||
|
|
||||||
src = builtins.path {
|
|
||||||
path = ./.;
|
|
||||||
name = "custominstall";
|
|
||||||
filter =
|
|
||||||
path: type:
|
|
||||||
!(builtins.elem (baseNameOf path) [
|
|
||||||
"build"
|
|
||||||
"dist"
|
|
||||||
"localtest"
|
|
||||||
"__pycache__"
|
|
||||||
"v"
|
|
||||||
".git"
|
|
||||||
"_build"
|
|
||||||
"custominstall.egg-info"
|
|
||||||
]);
|
|
||||||
};
|
|
||||||
|
|
||||||
doCheck = false;
|
|
||||||
|
|
||||||
build-system = [ setuptools ];
|
|
||||||
|
|
||||||
propagatedBuildInputs =
|
|
||||||
[
|
|
||||||
pyctr
|
|
||||||
pycryptodomex
|
|
||||||
setuptools
|
|
||||||
events
|
|
||||||
]
|
|
||||||
++ lib.optionals (withGUI) [
|
|
||||||
tkinter
|
|
||||||
];
|
|
||||||
|
|
||||||
makeWrapperArgs = [ "--set CUSTOM_INSTALL_SAVE3DS_PATH ${save3ds_no_fuse}/bin/save3ds_fuse" ];
|
|
||||||
|
|
||||||
preFixup = ''
|
|
||||||
rm -r $out/lib/${python.libPrefix}/site-packages/custominstall/bin
|
|
||||||
${lib.optionalString (!withGUI) "rm $out/bin/custominstall-gui"}
|
|
||||||
'';
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Installs a title directly to an SD card for the Nintendo 3DS";
|
|
||||||
homepage = "https://github.com/ihaveamac/custom-install";
|
|
||||||
license = licenses.mit;
|
|
||||||
platforms = platforms.unix;
|
|
||||||
mainProgram = "custominstall";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
[build-system]
|
|
||||||
requires = ["setuptools >= 61.0"]
|
|
||||||
build-backend = "setuptools.build_meta"
|
|
||||||
|
|
||||||
[project]
|
|
||||||
name = "custominstall"
|
|
||||||
description = "Installs a title directly to an SD card for the Nintendo 3DS"
|
|
||||||
authors = [
|
|
||||||
{ name = "Ian Burgwin", email = "ian@ianburgwin.net" },
|
|
||||||
]
|
|
||||||
readme = "README.md"
|
|
||||||
license = {text = "MIT"}
|
|
||||||
dynamic = ["version"]
|
|
||||||
requires-python = ">= 3.8"
|
|
||||||
classifiers = [
|
|
||||||
"Topic :: Utilities",
|
|
||||||
"License :: OSI Approved :: MIT License",
|
|
||||||
"Programming Language :: Python :: 3",
|
|
||||||
"Programming Language :: Python :: 3.8",
|
|
||||||
"Programming Language :: Python :: 3.9",
|
|
||||||
"Programming Language :: Python :: 3.10",
|
|
||||||
"Programming Language :: Python :: 3.11",
|
|
||||||
"Programming Language :: Python :: 3.12",
|
|
||||||
"Programming Language :: Python :: 3.13",
|
|
||||||
"Programming Language :: Python :: 3.14",
|
|
||||||
]
|
|
||||||
dependencies = [
|
|
||||||
"pyctr>=0.7.6,<0.9",
|
|
||||||
"setuptools>=61.0.0",
|
|
||||||
"events>=0.4",
|
|
||||||
"comtypes>=1.4.12; os_name == 'nt'",
|
|
||||||
]
|
|
||||||
|
|
||||||
[project.gui-scripts]
|
|
||||||
custominstall-gui = "custominstall.gui:main"
|
|
||||||
|
|
||||||
[project.scripts]
|
|
||||||
custominstall = "custominstall.__main__:main"
|
|
||||||
|
|
||||||
[tool.setuptools.dynamic]
|
|
||||||
version = {attr = "custominstall.__version__"}
|
|
||||||
|
|
||||||
[tool.setuptools.packages]
|
|
||||||
find = {namespaces = false}
|
|
||||||
|
|
||||||
# is it even possible to make these OS-specific with pyproject.toml?
|
|
||||||
[tool.setuptools.package-data]
|
|
||||||
custominstall = ["bin/darwin/save3ds_fuse", "bin/win32/save3ds_fuse.exe", "TaskbarLib.tlb", "title.db.gz", "custom-install-finalize.3dsx"]
|
|
||||||
2
requirements-win32.txt
Normal file
2
requirements-win32.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
-r requirements.txt
|
||||||
|
comtypes==1.1.10
|
||||||
2
requirements.txt
Normal file
2
requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
events==0.4
|
||||||
|
pyctr>=0.4,<0.7
|
||||||
19
setup-cxfreeze.py
Normal file
19
setup-cxfreeze.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import sys
|
||||||
|
from cx_Freeze import setup, Executable
|
||||||
|
|
||||||
|
if sys.platform == 'win32':
|
||||||
|
executables = [
|
||||||
|
Executable('ci-gui.py', target_name='ci-gui-console'),
|
||||||
|
Executable('ci-gui.py', target_name='ci-gui', base='Win32GUI'),
|
||||||
|
]
|
||||||
|
else:
|
||||||
|
executables = [
|
||||||
|
Executable('ci-gui.py', target_name='ci-gui'),
|
||||||
|
]
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name = "ci-gui",
|
||||||
|
version = "2.1b4",
|
||||||
|
description = "Installs a title directly to an SD card for the Nintendo 3DS",
|
||||||
|
executables = executables
|
||||||
|
)
|
||||||
13
windows-install-dependencies.py
Normal file
13
windows-install-dependencies.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# This is meant to be double-clicked from File Explorer.
|
||||||
|
|
||||||
|
# This doesn't import pip as a module in case the way it's executed changes, which it has in the past.
|
||||||
|
# Instead we call it like we would in the command line.
|
||||||
|
|
||||||
|
from subprocess import run
|
||||||
|
from os.path import dirname, join
|
||||||
|
from sys import executable
|
||||||
|
|
||||||
|
root_dir = dirname(__file__)
|
||||||
|
|
||||||
|
run([executable, '-m', 'pip', 'install', '--user', '-r', join(root_dir, 'requirements-win32.txt')])
|
||||||
|
input('Press enter to close')
|
||||||
Reference in New Issue
Block a user