Files
libretro/schemas/install-manifest.schema.json
T

953 lines
30 KiB
JSON

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://abdess.github.io/retrobios/api/v1/schemas/install-manifest.schema.json",
"title": "RetroBIOS installer manifest",
"type": "object",
"additionalProperties": false,
"required": [
"manifest_version",
"source",
"regions",
"platform",
"display_name",
"version",
"generated",
"base_destination",
"detect",
"standalone_copies",
"total_files",
"total_size",
"total_omitted",
"omitted_files",
"files"
],
"properties": {
"manifest_version": {
"const": 2
},
"source": {
"enum": [
"full",
"platform",
"truth"
]
},
"regions": {
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
},
"target": {
"type": "string",
"minLength": 1,
"description": "Hardware target this manifest was filtered for, absent when unfiltered"
},
"categorized": {
"description": "Every game data file carries category: game_data. Without it the list records no category, and the installer refuses --no-game-data.",
"const": true
},
"no_game_data": {
"description": "Built without game data, absent when the game data is listed",
"const": true
},
"platform": {
"type": "string",
"minLength": 1,
"description": "Registry key of the platform (batocera)."
},
"display_name": {
"type": "string",
"minLength": 1,
"description": "Name the site shows for the platform."
},
"version": {
"type": "string",
"description": "Version of the platform's own list this manifest was built from."
},
"generated": {
"type": "string",
"format": "date-time",
"description": "When the manifest was written."
},
"base_destination": {
"type": "string",
"description": "The BIOS folder entries are written below, as the platform names it. Empty when entries start one level higher (RetroDECK)."
},
"detect": {
"type": "array",
"items": {
"type": "object"
}
},
"standalone_copies": {
"type": "array",
"items": {
"type": "object"
}
},
"total_files": {
"type": "integer",
"minimum": 0,
"description": "Number of entries in files."
},
"total_size": {
"type": "integer",
"minimum": 0,
"description": "Bytes of the files in files."
},
"pack_files": {
"description": "Files the platform's pack holds once extracted: this list, the data directories and the pack's own documents.",
"type": "integer",
"minimum": 0
},
"pack_size": {
"description": "Bytes those files occupy once extracted.",
"type": "integer",
"minimum": 0
},
"total_omitted": {
"type": "integer",
"minimum": 0,
"description": "Number of entries in omitted_files."
},
"core_names": {
"description": "Each core a file names, with the other names it goes by upstream (the buildbot's mednafen_psx for beetle_psx).",
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
}
},
"system_cores": {
"description": "Each platform system with the cores whose presence keeps it. A system absent here is kept whatever cores are available.",
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
}
},
"system_names": {
"description": "Each platform system with the names the platform's own file gives it (native_system), which the installer accepts for --system.",
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
}
},
"omitted_files": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"dest",
"name",
"system",
"required",
"reason",
"cores"
],
"properties": {
"dest": {
"type": "string",
"pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$"
},
"name": {
"type": "string",
"minLength": 1
},
"system": {
"type": "string"
},
"required": {
"type": "boolean"
},
"reason": {
"enum": [
"hash_mismatch",
"not_found",
"external",
"user_provided",
"no_platform_slug",
"below_platform_folder",
"no_save_directory",
"no_core_folder",
"no_save_system"
]
},
"category": {
"description": "game_data: a game's own data, not firmware. Absent on firmware.",
"const": "game_data"
},
"held": {
"description": "The pack builder holds this file and the installer cannot download it. Region narrowing counts it held, as the builder does, so it displaces the same fallback.",
"const": true
},
"cores": {
"oneOf": [
{
"type": "null"
},
{
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
}
]
},
"regions": {
"description": "The regions the emulator code selects the file for. Absent when it never competes.",
"type": "array",
"items": {
"type": "string",
"enum": [
"argentina",
"asia",
"asia-ntsc",
"asia-pal",
"australia",
"brazil",
"canada",
"china",
"denmark",
"europe",
"finland",
"france",
"germany",
"greece",
"hong-kong",
"india",
"italy",
"japan",
"latin-america",
"mexico",
"netherlands",
"new-zealand",
"north-america",
"norway",
"oceania",
"poland",
"portugal",
"russia",
"singapore",
"south-korea",
"spain",
"sweden",
"taiwan",
"uk",
"world"
]
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"region_groups": {
"description": "Groups the file competes in as a core extra, whatever systems are chosen.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"region_system_groups": {
"description": "Groups the file competes in as the platform's own declaration: present only when that system is kept.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"systems": {
"description": "Every platform system that declares the file, for the installer's --system.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"priority": {
"description": "The rank the code searches the file at, lower first: a world file withdraws an unmatched regional one only when it ranks no worse.",
"type": "integer"
},
"declared_in": {
"description": "The platform systems declaring the file, when fewer than `systems`, which also names the systems whose cores read it there.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
},
"alternatives": {
"description": "Cores claiming this destination behind the platform's own declaration, in the order the pack builder tries them. A narrowing that drops every declaring system takes the first whose cores remain.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"cores"
],
"properties": {
"cores": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
}
}
}
},
"root": {
"description": "save: dest is relative to the save directory the frontend hands the core (RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY), not to the BIOS directory. Absent for a file of the BIOS tree.",
"const": "save"
},
"core_folder": {
"description": "The core's library_name, the folder a frontend sorting saves by core (RetroArch's sort_savefiles_enable) inserts between its save directory and dest. Only with root: save. Absent on a save entry when the core reads the same place sorted or not.",
"type": "string",
"minLength": 1,
"pattern": "^[^/\\\\]+$"
}
}
},
"description": "Files the pack needs and the repository cannot serve, with the reason."
},
"files": {
"type": "array",
"items": {
"$ref": "#/$defs/file"
},
"description": "Every file the installer fetches, one entry per destination."
},
"case_variants": {
"description": "Files the folded list serves under another case, installed only where the target directory keeps case.",
"type": "array",
"items": {
"$ref": "#/$defs/file"
}
},
"data_directories": {
"description": "Data trees the pack carries, rebuilt by the installer from their source archive. Each file is kept only when its sha1 matches.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"ref",
"dest",
"url",
"type",
"systems",
"files"
],
"properties": {
"ref": {
"type": "string"
},
"dest": {
"type": "string",
"pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).*$"
},
"url": {
"type": "string",
"pattern": "^https://"
},
"type": {
"enum": [
"zip",
"tarball"
]
},
"strip_components": {
"type": "integer",
"minimum": 0
},
"source_path": {
"type": "string"
},
"exclude": {
"type": "array",
"items": {
"type": "string"
}
},
"systems": {
"type": "array",
"items": {
"type": "string"
}
},
"files": {
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"required": [
"sha1",
"size"
],
"properties": {
"sha1": {
"type": "string",
"pattern": "^[a-f0-9]{40}$"
},
"size": {
"type": "integer",
"minimum": 0
}
}
}
}
}
}
},
"save_directory": {
"description": "Where the platform keeps the save directory its frontend hands a core, present when an entry carries root: save. folder is the pack folder holding those files and the save directory's default place beside the BIOS directory, and by_core says the frontend appends each core's library_name (core_folder).",
"type": "object",
"additionalProperties": false,
"required": [
"folder",
"by_core"
],
"properties": {
"folder": {
"type": "string",
"pattern": "^[^/\\\\.][^/\\\\]*(/[^/\\\\.][^/\\\\]*)*$"
},
"by_core": {
"type": "boolean"
},
"by_system": {
"description": "true when the platform's launcher hands each core <save directory>/<system> at each launch (Batocera, RetroBat). Each dest then starts with that system's folder, and no frontend config read at install time changes it.",
"const": true
}
}
}
},
"$defs": {
"file": {
"type": "object",
"additionalProperties": false,
"required": [
"dest",
"sha1",
"sha256",
"size",
"repo_path",
"cores"
],
"properties": {
"dest": {
"type": "string",
"pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$)).+$",
"description": "Path below base_destination, or below the save directory when root is save."
},
"sha1": {
"type": "string",
"pattern": "^[a-f0-9]{40}$",
"description": "SHA1 of the copy the repository serves. The installer checks it after download."
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$",
"description": "SHA256 of the same copy."
},
"size": {
"type": "integer",
"minimum": 0,
"description": "Bytes of the same copy."
},
"repo_path": {
"type": "string",
"description": "Path in the repository. Fetched from https://raw.githubusercontent.com/Abdess/retrobios/<ref>/<repo_path>, ref being main unless RETROBIOS_REF names a tag."
},
"cores": {
"oneOf": [
{
"type": "null"
},
{
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
}
],
"description": "Profiles whose core brings the file into the pack. Null for a file the platform's own list declares."
},
"storage": {
"const": "release",
"description": "release when the file is a large-files release asset."
},
"release_asset": {
"type": "string",
"pattern": "^[^/\\\\]+$",
"description": "Asset of the large-files release, fetched from https://github.com/Abdess/retrobios/releases/download/large-files/<asset> instead of repo_path."
},
"systems": {
"description": "Every platform system that declares the file, for the installer's --system.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"regions": {
"description": "The regions the emulator code selects the file for. Absent when it never competes.",
"type": "array",
"items": {
"type": "string",
"enum": [
"argentina",
"asia",
"asia-ntsc",
"asia-pal",
"australia",
"brazil",
"canada",
"china",
"denmark",
"europe",
"finland",
"france",
"germany",
"greece",
"hong-kong",
"india",
"italy",
"japan",
"latin-america",
"mexico",
"netherlands",
"new-zealand",
"north-america",
"norway",
"oceania",
"poland",
"portugal",
"russia",
"singapore",
"south-korea",
"spain",
"sweden",
"taiwan",
"uk",
"world"
]
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"region_groups": {
"description": "Groups the file competes in as a core extra, whatever systems are chosen.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"region_system_groups": {
"description": "Groups the file competes in as the platform's own declaration: present only when that system is kept.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"priority": {
"description": "The rank the code searches the file at, lower first: a world file withdraws an unmatched regional one only when it ranks no worse.",
"type": "integer"
},
"alternatives": {
"description": "Copies other cores read at this destination when they disagree on its content, in the order the pack builder tries them. A narrowing that drops the entry's cores takes the first whose cores remain.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"sha1",
"sha256",
"size",
"repo_path",
"cores"
],
"properties": {
"sha1": {
"type": "string",
"pattern": "^[a-f0-9]{40}$"
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"size": {
"type": "integer",
"minimum": 0
},
"repo_path": {
"type": "string"
},
"storage": {
"const": "release"
},
"release_asset": {
"type": "string",
"pattern": "^[^/\\\\]+$"
},
"cores": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"executable": {
"type": "boolean"
}
}
}
},
"slot_choices": {
"description": "On a platform file a core's own source contradicts while the frontend only checks the path: the copy each core's presence puts there, in the order the pack builder settles the slot. A narrowing serves the first whose cores remain. One naming only cores, or none remaining, leaves `declared_choices`.",
"type": "array",
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"cores"
],
"properties": {
"sha1": {
"type": "string",
"pattern": "^[a-f0-9]{40}$"
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"size": {
"type": "integer",
"minimum": 0
},
"repo_path": {
"type": "string"
},
"storage": {
"const": "release"
},
"release_asset": {
"type": "string",
"pattern": "^[^/\\\\]+$"
},
"cores": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1,
"uniqueItems": true
},
"executable": {
"type": "boolean"
}
}
}
},
"declared_choices": {
"description": "The platform's own answer at the destination by the declaring systems that remain, in the order the pack builder takes the declarations. A narrowing serves the first whose systems remain.",
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"sha1",
"sha256",
"size",
"repo_path",
"systems"
],
"properties": {
"sha1": {
"type": "string",
"pattern": "^[a-f0-9]{40}$"
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"size": {
"type": "integer",
"minimum": 0
},
"repo_path": {
"type": "string"
},
"storage": {
"const": "release"
},
"release_asset": {
"type": "string",
"pattern": "^[^/\\\\]+$"
},
"executable": {
"type": "boolean"
},
"systems": {
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"minItems": 1,
"uniqueItems": true
}
}
}
},
"category": {
"description": "game_data: a game's own data, not firmware. Absent on firmware. The installer's --no-game-data leaves these out, as a pack built with --no-game-data does.",
"const": "game_data"
},
"executable": {
"description": "The repository keeps the file executable, and the installer gives it the execute bits the umask allows.",
"type": "boolean"
},
"declared_in": {
"description": "The platform systems declaring the file, when fewer than `systems`, which also names the systems whose cores read it there.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
},
"absent_claims": {
"description": "Cores that want this destination and have nothing held, after the cores served here: a narrowing that keeps none of those takes the first named one as a file left out, as a pack built for it lists it.",
"type": "array",
"minItems": 1,
"items": {
"type": "object",
"additionalProperties": false,
"required": [
"name",
"system",
"required",
"reason",
"cores"
],
"properties": {
"name": {
"type": "string",
"minLength": 1
},
"system": {
"type": "string"
},
"required": {
"type": "boolean"
},
"reason": {
"enum": [
"hash_mismatch",
"not_found",
"external",
"user_provided",
"no_platform_slug",
"below_platform_folder"
]
},
"cores": {
"oneOf": [
{
"type": "null"
},
{
"type": "array",
"items": {
"type": "string"
},
"uniqueItems": true
}
]
},
"regions": {
"description": "The regions the emulator code selects the file for. Absent when it never competes.",
"type": "array",
"items": {
"type": "string",
"enum": [
"argentina",
"asia",
"asia-ntsc",
"asia-pal",
"australia",
"brazil",
"canada",
"china",
"denmark",
"europe",
"finland",
"france",
"germany",
"greece",
"hong-kong",
"india",
"italy",
"japan",
"latin-america",
"mexico",
"netherlands",
"new-zealand",
"north-america",
"norway",
"oceania",
"poland",
"portugal",
"russia",
"singapore",
"south-korea",
"spain",
"sweden",
"taiwan",
"uk",
"world"
]
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"region_groups": {
"description": "Groups the file competes in as a core extra, whatever systems are chosen.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"region_system_groups": {
"description": "Groups the file competes in as the platform's own declaration: present only when that system is kept.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"systems": {
"description": "Every platform system that declares the file, for the installer's --system.",
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 256
},
"minItems": 1,
"maxItems": 1000,
"uniqueItems": true
},
"priority": {
"description": "The rank the code searches the file at, lower first: a world file withdraws an unmatched regional one only when it ranks no worse.",
"type": "integer"
},
"declared_in": {
"description": "The platform systems declaring the file, when fewer than `systems`, which also names the systems whose cores read it there.",
"type": "array",
"items": {
"type": "string",
"minLength": 1
},
"uniqueItems": true
}
}
}
},
"root": {
"description": "save: dest is relative to the save directory the frontend hands the core (RETRO_ENVIRONMENT_GET_SAVE_DIRECTORY), not to the BIOS directory. Absent for a file of the BIOS tree.",
"const": "save"
},
"core_folder": {
"description": "The core's library_name, the folder a frontend sorting saves by core (RetroArch's sort_savefiles_enable) inserts between its save directory and dest. Only with root: save. Absent on a save entry when the core reads the same place sorted or not.",
"type": "string",
"minLength": 1,
"pattern": "^[^/\\\\]+$"
}
},
"oneOf": [
{
"required": [
"release_asset"
]
},
{
"properties": {
"repo_path": {
"type": "string",
"pattern": "^bios/"
}
},
"not": {
"required": [
"release_asset"
]
}
}
]
}
},
"description": "What a platform's pack installs, one file per entry, as install.py reads it. The platform's list says what the setup checks, this list says what the pack writes: the list's files plus every file the setup's cores load."
}