diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 7bd5f9f..aa4d6ea 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -2,10 +2,34 @@ "version": 1, "isRoot": true, "tools": { - "cake.tool": { - "version": "2.2.0", + "gitversion.tool": { + "version": "5.12.0", "commands": [ - "dotnet-cake" + "dotnet-gitversion" + ] + }, + "thirdlicense": { + "version": "1.3.1", + "commands": [ + "thirdlicense" + ] + }, + "dotnet-reportgenerator-globaltool": { + "version": "5.2.0", + "commands": [ + "reportgenerator" + ] + }, + "docfx": { + "version": "2.74.0", + "commands": [ + "docfx" + ] + }, + "gitreleasemanager.tool": { + "version": "0.16.0", + "commands": [ + "dotnet-gitreleasemanager" ] } } diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 8453355..0000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM mcr.microsoft.com/vscode/devcontainers/dotnet:6.0 - -# Install Mono (for DocFX) -RUN apt install -y apt-transport-https dirmngr gnupg ca-certificates \ - && apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF \ - && echo "deb https://download.mono-project.com/repo/debian stable-buster main" >> /etc/apt/sources.list.d/mono-official-stable.list \ - && apt update \ - && export DEBIAN_FRONTEND=noninteractive \ - && apt install -y mono-devel diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 77f5949..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "Dev (.NET 6 and Mono)", - "build": { - "dockerfile": "Dockerfile", - }, - - "extensions": [ - "ms-dotnettools.csharp", - "shardulm94.trailing-spaces", - "cake-build.cake-vscode", - "streetsidesoftware.code-spell-checker", - "hediet.vscode-drawio", - "esbenp.prettier-vscode", - "yzhang.markdown-all-in-one", - "davidanson.vscode-markdownlint", - "eamodio.gitlens" - ], - - "remoteUser": "vscode", - - // PODMAN ONLY. You may need to remove this line for Docker. - // SELinux issues: https://github.com/containers/podman/issues/3683 - "runArgs": [ "--security-opt", "label=disable", "--userns=keep-id" ], - - // Podman issues: https://github.com/microsoft/vscode-remote-release/issues/3231 - "containerEnv": { - "HOME": "/home/vscode" - } -} \ No newline at end of file diff --git a/src/.editorconfig b/.editorconfig similarity index 61% rename from src/.editorconfig rename to .editorconfig index 1532274..3f1e627 100644 --- a/src/.editorconfig +++ b/.editorconfig @@ -1,16 +1,39 @@ # Top-level config file root = true +# All files +[*] +indent_style = space + +[*.yml] +indent_size = 2 + +[*.md] +charset = utf-8 +insert_final_newline = true +end_of_line = unset # Leave it to git +indent_style = space +indent_size = 2 +max_line_length = 80 + +# XML project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# XML config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + # Generic C# files -[*.cs] +[*.{cs,vb}] ## Generic options -charset = utf-8 +charset = utf-8-bom indent_size = 4 indent_style = space tab_width = 8 trim_trailing_whitespace = true -end_of_line = lf +end_of_line = unset # Leave it to git insert_final_newline = true ## .NET style rules @@ -31,6 +54,7 @@ dotnet_style_predefined_type_for_member_access = true:warning ### Modifier preferences dotnet_style_require_accessibility_modifiers = for_non_interface_members:warning +dotnet_diagnostic.SA1400.severity = warning # it doesn't follow the above value dotnet_style_readonly_field = true:warning ### Parentheses preferences @@ -45,16 +69,16 @@ dotnet_style_collection_initializer = true:warning dotnet_style_explicit_tuple_names = true:warning dotnet_style_prefer_inferred_tuple_names = true:suggestion dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion -dotnet_style_prefer_auto_properties = true:warning +dotnet_style_prefer_auto_properties = true:suggestion dotnet_style_prefer_conditional_expression_over_assignment = true:warning -dotnet_style_prefer_conditional_expression_over_return = true:suggestion -dotnet_style_prefer_compound_assignment = true:warning +dotnet_style_prefer_conditional_expression_over_return = true:warning +dotnet_style_prefer_compound_assignment = true:suggestion dotnet_style_prefer_simplified_interpolation = true:warning dotnet_style_prefer_simplified_boolean_expressions = true:warning dotnet_style_operator_placement_when_wrapping = end_of_line ### Null-checking preferences -dotnet_style_coalesce_expression = true:warning +dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:warning dotnet_style_prefer_is_null_check_over_reference_equality_method = true:warning @@ -67,23 +91,25 @@ dotnet_remove_unnecessary_suppression_exclusions = none csharp_style_var_for_built_in_types = false:warning csharp_style_var_when_type_is_apparent = true:suggestion csharp_style_var_elsewhere = false:suggestion +dotnet_diagnostic.IDE0008.severity = suggestion # Doesn't follow above values ### Expression-bodied members -csharp_style_expression_bodied_methods = when_on_single_line:suggestion +csharp_style_expression_bodied_methods = false csharp_style_expression_bodied_constructors = false:suggestion csharp_style_expression_bodied_operators = true:suggestion -csharp_style_expression_bodied_properties = when_on_single_line:warning -csharp_style_expression_bodied_indexers = when_on_single_line:warning -csharp_style_expression_bodied_accessors = when_on_single_line:warning -csharp_style_expression_bodied_lambdas = when_on_single_line:warning +csharp_style_expression_bodied_properties = when_on_single_line:suggestion +csharp_style_expression_bodied_indexers = when_on_single_line:suggestion +csharp_style_expression_bodied_accessors = when_on_single_line:suggestion +csharp_style_expression_bodied_lambdas = when_on_single_line:suggestion csharp_style_expression_bodied_local_functions = when_on_single_line:suggestion ### Pattern matching preferences csharp_style_pattern_matching_over_is_with_cast_check = true:warning csharp_style_pattern_matching_over_as_with_null_check = true:warning -csharp_style_prefer_switch_expression = true:warning -csharp_style_prefer_pattern_matching = true:warning +csharp_style_prefer_switch_expression = true:suggestion +csharp_style_prefer_pattern_matching = true:suggestion csharp_style_prefer_not_pattern = true:warning +csharp_style_prefer_null_check_over_type_check = true:suggestion ### Expression-level preferences csharp_style_inlined_variable_declaration = true:warning @@ -95,25 +121,36 @@ csharp_style_prefer_range_operator = true:warning csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion csharp_style_unused_value_assignment_preference = discard_variable:warning csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion +csharp_style_prefer_method_group_conversion = true:suggestion +csharp_style_prefer_local_over_anonymous_function = true:suggestion ### Null-checking preferences csharp_style_throw_expression = true:warning csharp_style_conditional_delegate_call = true:warning ### Code-block preferences -csharp_prefer_braces = when_multiline:error +csharp_prefer_braces = true:warning +dotnet_diagnostic.SA1503.severity = warning # Doesn't follow above value csharp_prefer_simple_using_statement = true:suggestion +csharp_style_prefer_tuple_swap = true:suggestion ### 'using' directive preferences -csharp_using_directive_placement = outside_namespace:warning +csharp_using_directive_placement = inside_namespace:warning +dotnet_diagnostic.SA1200.severity = warning # Doesn't follow above value ### Modifier preferences csharp_prefer_static_local_function = true:warning csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:warning +### New C# features +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_utf8_string_literals = true:suggestion +csharp_style_prefer_readonly_struct = true:suggestion +csharp_style_prefer_readonly_struct_member = true:suggestion + ## C# formatting rules ### New line preferences -csharp_new_line_before_open_brace = local_functions,methods,types +csharp_new_line_before_open_brace = methods,types csharp_new_line_before_else = false csharp_new_line_before_catch = false csharp_new_line_before_finally = false @@ -128,6 +165,7 @@ csharp_indent_labels = one_less_than_current csharp_indent_block_contents = true csharp_indent_braces = false csharp_indent_case_contents_when_block = false +csharp_style_namespace_declarations = file_scoped ### Spacing preferences csharp_space_after_cast = false @@ -157,32 +195,65 @@ csharp_space_between_square_brackets = false csharp_preserve_single_line_statements = false csharp_preserve_single_line_blocks = true +### Top level statement +csharp_style_prefer_top_level_statements = true:silent + ## Naming styles rules +dotnet_style_namespace_match_folder = true:warning dotnet_diagnostic.IDE1006.severity = warning +dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_rule.types_should_be_pascal_case.severity = warning +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +### Symbol specifications +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + ## Code analyzers ### .NET SDK dotnet_diagnostic.CA1303.severity = none # We don't translate exception and log messages from English +dotnet_diagnostic.SA1025.severity = none # Allow spaces in comments to structure info +dotnet_diagnostic.IDE0045.severity = suggestion # Simplify ifs +dotnet_diagnostic.IDE0046.severity = suggestion # Simplify ifs ### StyleCop -dotnet_diagnostic.SA1009.severity = none # False positive due to nullables -dotnet_diagnostic.SA1011.severity = none # False positive due to nullables dotnet_diagnostic.SA1101.severity = none # Do not force to prefix local calls with 'this' -dotnet_diagnostic.SA1137.severity = none # False positive due to inline methods +dotnet_diagnostic.SA1204.severity = suggestion # Static methods should be before non-static dotnet_diagnostic.SA1500.severity = none # Allow inline braces -dotnet_diagnostic.SA1503.severity = suggestion # Braces can be omitted (guards can) dotnet_diagnostic.SA1633.severity = none # No XML-format header in source files -dotnet_diagnostic.SA1200.severity = none # Namespace outside - -### IDE -dotnet_diagnostic.IDE0058.severity = suggestion # Expression value is never used ### SonarAnalyzer +dotnet_diagnostic.S1133.severity = suggestion # Remove deprecated code -.-' I know, some day dotnet_diagnostic.S1135.severity = suggestion # It's almost inevitable to have TODO but add bug ID -dotnet_diagnostic.S1172.severity = silent # Buggy # Special rules for test projects -[{*Tests/**,*Examples/**}] +[{src/*Tests/**,src/*Examples/**}] dotnet_diagnostic.CS1591.severity = none # Disable documentation dotnet_diagnostic.CA1001.severity = none # No need to implement IDisposable in test classes with cleanup. dotnet_diagnostic.CA1034.severity = none # Public types in test classes for testing implementations @@ -192,11 +263,15 @@ dotnet_diagnostic.CA1305.severity = none # No culture method for quick test code dotnet_diagnostic.CA1307.severity = none # No culture method for quick test code dotnet_diagnostic.SA0001.severity = none # Disable documentation dotnet_diagnostic.SA1600.severity = none # Disable documentation +dotnet_diagnostic.SA1201.severity = none # Allow enums inside classes +dotnet_diagnostic.S1144.severity = none # Remove unused setter +dotnet_diagnostic.S2094.severity = none # Remove empty class dotnet_diagnostic.S2699.severity = none # Assert may be in helper methods dotnet_diagnostic.S3966.severity = none # Dispose twice to test implementation +dotnet_code_quality_unused_parameters = all:none # Some test methods may not use all the source args # Special rules for example projects -[*Examples/**] +[src/*Examples/**] dotnet_diagnostic.SA1123.severity = none # We can have regions inside methods dotnet_diagnostic.SA1515.severity = none # Allow comment lines after region dotnet_diagnostic.S1481.severity = none # Unused variables diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 5280c34..cddcba4 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -6,29 +6,22 @@ labels: "" assignees: "" --- -**Describe the bug** -A clear and concise description of what the bug is. +## Description -**To Reproduce** -Steps to reproduce the behavior: +TODO: describe the issue -1. Get the library from '...' and version '...' -2. Use the class and method '....' -3. See error +## Reproducer -**Expected behavior** -A clear and concise description of what you expected to happen. +TODO: steps to reproduce the behavior. -**Exceptions** -If applicable, the full exception stacktrace that you get. +## Expected behavior -**Screenshots** -If applicable, add screenshots to help explain your problem. +TODO: description of the expected behavior. -**Desktop (please complete the following information):** +## Report info -- OS: [e.g. Windows, Linux, Mac] -- Version [e.g. 22] +TODO: if applicable, the full exception stacktrace that you get. -**Additional context** -Add any other context about the problem here. +TODO: if applicable, add screenshots to help explain your problem. + +TODO: describe your environment like OS, app/lib version diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7..8f080c9 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,20 +1,23 @@ --- name: Feature request about: Suggest an idea for this project -title: '' -labels: '' -assignees: '' - +title: "" +labels: "" +assignees: "" --- -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] +## Goal + +TODO: describe with user stories or a short text the goal of the feature. + +## Description + +TODO: describe the motivation behind of the idea and what it should do. + +## Proposed solution -**Describe the solution you'd like** -A clear and concise description of what you want to happen. +TODO: add any ideas for the implementation or how it should look like. -**Describe alternatives you've considered** -A clear and concise description of any alternative solutions or features you've considered. +## Acceptance criteria -**Additional context** -Add any other context or screenshots about the feature request here. +TODO: list of expectations it should pass to close the request. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4b35deb..529af20 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,9 +1,22 @@ -### Description +TODO: description of the PR work. -A clear and concise description of what the bug or feature is. +This PR closes # -### Example +## Quality check list -Small example on how to use the new classes and methods. +- [ ] Related code has been tested automatically or manually +- [ ] Related documentation is updated +- [ ] I acknowledge I have read and filled this checklist and accept the + [developer certificate of origin](https://developercertificate.org/) -This closes # +## Acceptance criteria + +TODO: list of expectations it has passed from the related issue. + +## Follow-up work + +TODO: describe any missing or future required work. + +## Example + +TODO: small code-snippet or screenshot of the work diff --git a/.github/workflows/build-and-release.yml b/.github/workflows/build-and-release.yml index 5e0fbc3..b5d506f 100644 --- a/.github/workflows/build-and-release.yml +++ b/.github/workflows/build-and-release.yml @@ -9,137 +9,27 @@ on: branches: [ main ] # Stable tags: [ "v*" ] - release: - types: - - published - -env: - NET_SDK: '6.0.302' - RESOURCES_VERSION: '1.0' jobs: - build_main: - name: "[ubuntu-latest] Build, test and stage" - runs-on: ubuntu-latest - steps: - - name: "Checkout" - uses: actions/checkout@v2 - with: - fetch-depth: 0 # We need full history for version number - lfs: true - submodules: 'recursive' - - - name: "Setup .NET SDK" - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.NET_SDK }} - - - name: "Install build tools" - run: dotnet tool restore - - - name: "Generate release notes" - run: dotnet cake --target=Generate-ReleaseNotes --verbosity=diagnostic - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Cache test resources - uses: actions/cache@v3 - with: - path: resources - key: ${{ runner.os }}-tests-${{ env.RESOURCES_VERSION }} - - - name: "Build, test and stage" - run: dotnet cake --target=Stage-Artifacts --configuration=Release --resource-uri=${{secrets.TEST_RESOURCES_URI_V1}} - - - name: "Publish test results" - uses: actions/upload-artifact@v2 - with: - name: "Test results" - path: "./artifacts/test_results" - retention-days: 1 - - - name: "Publish artifacts to CI" - uses: actions/upload-artifact@v2 - with: - name: "Artifacts" - path: | - ./artifacts/*.zip - ./artifacts/*.nupkg - ./artifacts/*.snupkg - retention-days: 2 - - build_sec: - name: "[${{ matrix.os }}] Build and test" - strategy: - matrix: - os: [ macos-latest, windows-latest ] - runs-on: ${{ matrix.os }} - steps: - - name: "Checkout" - uses: actions/checkout@v2 - with: - fetch-depth: 0 # We need full history for version number - lfs: true - submodules: 'recursive' - - - name: "Setup .NET SDK" - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.NET_SDK }} - - - name: "Install build tools" - run: dotnet tool restore - - - name: Cache test resources - uses: actions/cache@v3 - with: - path: resources - key: ${{ runner.os }}-tests-${{ env.RESOURCES_VERSION }} - - # No need to stage as one job can create the binaries for all platforms - - name: "Build and test" - run: dotnet cake --target=BuildTest --configuration=Release --resource-uri=${{secrets.TEST_RESOURCES_URI_V1}} - - # Preview release on push to develop only + build: + name: "Build" + uses: ./.github/workflows/build.yml + with: + dotnet_version: '8.0.100' + secrets: + test_resources: ${{ secrets.TEST_RESOURCES_URI_V1 }} + + # Preview release on push to main only # Stable release on version tag push only - push_artifacts: - name: "Push artifacts" + deploy: + name: "Deploy" if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v') - needs: [ "build_main", "build_sec" ] - runs-on: ubuntu-latest - env: - # Needed only for Azure DevOps Artifacts due to its weird auth method. - PREVIEW_NUGET_FEED: 'https://pkgs.dev.azure.com/SceneGate/SceneGate/_packaging/SceneGate-Preview/nuget/v3/index.json' - steps: - - name: "Checkout" - uses: actions/checkout@v2 - with: - fetch-depth: 0 # We need full history for version number - submodules: 'recursive' - - - name: "Download artifacts" - uses: actions/download-artifact@v2 - with: - name: "Artifacts" - path: "./artifacts" - - - name: "Setup .NET SDK" - uses: actions/setup-dotnet@v1 - with: - dotnet-version: ${{ env.NET_SDK }} - - - name: "Install build tools" - run: dotnet tool restore - - # Weird way to authenticate in Azure DevOps Artifacts - # Then, we need to setup VSS_NUGET_EXTERNAL_FEED_ENDPOINTS - - name: "Install Azure Artifacts Credential Provider" - run: wget -qO- https://aka.ms/install-artifacts-credprovider.sh | bash - - - name: "Publish artifacts" - run: dotnet cake --target=Push-Artifacts --verbosity=diagnostic - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - STABLE_NUGET_FEED_TOKEN: ${{ secrets.STABLE_NUGET_FEED_TOKEN }} - PREVIEW_NUGET_FEED_TOKEN: "az" # Dummy, auth via below env var - VSS_NUGET_EXTERNAL_FEED_ENDPOINTS: '{"endpointCredentials": [{"endpoint":"${{ env.PREVIEW_NUGET_FEED }}", "username":"", "password":"${{ secrets.PREVIEW_NUGET_FEED_TOKEN }}"}]}' + needs: build + uses: ./.github/workflows/deploy.yml + with: + dotnet_version: '8.0.100' + azure_nuget_feed: 'https://pkgs.dev.azure.com/SceneGate/SceneGate/_packaging/SceneGate-Preview/nuget/v3/index.json' + secrets: + nuget_preview_token: "az" # Dummy values as we use Azure DevOps onlyg + nuget_stable_token: "${{ secrets.NUGET_FEED_TOKEN }}" + azure_nuget_token: ${{ secrets.ADO_NUGET_FEED_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a9d7937 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,60 @@ +name: "Build" + +on: + workflow_call: + inputs: + dotnet_version: + required: true + type: string + secrets: + test_resources: + required: true + +jobs: + build: + strategy: + matrix: + os: [ ubuntu-latest, macos-latest, windows-latest ] + include: + # By default they are no "main build" but if it matches "os" then yes. + - os: ubuntu-latest + is_main_build: true + name: "${{ matrix.os }}" + runs-on: ${{ matrix.os }} + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 # We need full history for version number + + - name: "Setup .NET SDK" + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ inputs.dotnet_version }} + + - name: "Build and test" + run: dotnet run --project build/orchestrator -- --resource-uri=${{ secrets.test_resources }} --target=Default --dotnet-configuration=Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "Bundle" + if: ${{ matrix.is_main_build }} + run: dotnet run --project build/orchestrator -- --target=Bundle --dotnet-configuration=Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: "Publish artifacts to CI" + if: ${{ matrix.is_main_build }} + uses: actions/upload-artifact@v3 + with: + name: "Artifacts" + retention-days: 7 + path: | + build/artifacts/ + !build/artifacts/docs + + - name: Publish docs artifact to CI + if: ${{ matrix.is_main_build }} + uses: actions/upload-pages-artifact@v2 + with: + path: build/artifacts/docs diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 0000000..7039796 --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,68 @@ +name: "Deploy" + +on: + workflow_call: + inputs: + dotnet_version: + required: true + type: string + azure_nuget_feed: + required: false + type: string + secrets: + nuget_preview_token: + required: false + nuget_stable_token: + required: false + azure_nuget_token: + required: false + +jobs: + upload_doc: + name: "Documentation" + runs-on: "ubuntu-latest" + # Grant GITHUB_TOKEN the permissions required to make a Pages deployment + permissions: + pages: write # to deploy to Pages + id-token: write # to verify the deployment originates from an appropriate source + # Deploy to the github-pages environment + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 + + push_artifacts: + name: "Artifacts" + runs-on: "ubuntu-latest" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 # We need full history for version number + + - name: "Download artifacts" + uses: actions/download-artifact@v3 + with: + name: "Artifacts" + path: "./build/artifacts/" + + - name: "Setup .NET SDK" + uses: actions/setup-dotnet@v3 + with: + dotnet-version: ${{ inputs.dotnet_version }} + + # Weird way to authenticate in Azure DevOps Artifacts + # Then, we need to setup VSS_NUGET_EXTERNAL_FEED_ENDPOINTS + - name: "Install Azure Artifacts Credential Provider" + run: wget -qO- https://aka.ms/install-artifacts-credprovider.sh | bash + + - name: "Deploy artifacts" + run: dotnet run --project build/orchestrator -- --target=Deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + STABLE_NUGET_FEED_TOKEN: ${{ secrets.nuget_stable_token }} + PREVIEW_NUGET_FEED_TOKEN: ${{ secrets.nuget_preview_token }} + VSS_NUGET_EXTERNAL_FEED_ENDPOINTS: '{"endpointCredentials": [{"endpoint":"${{ inputs.azure_nuget_feed }}", "username":"", "password":"${{ secrets.azure_nuget_token }}"}]}' diff --git a/.gitignore b/.gitignore index d39debf..f56fd9a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,18 @@ # Build outputs obj/ bin/ -artifacts/ - -# Build system -tools/ - -# Test results -test_results/ -BenchmarkDotNet.Artifacts/ - -# Documentation output -docs/_site -docs/api -docs/_site_pdf +build/artifacts/ +build/temp/ +/CHANGELOG.md +/CHANGELOG.NEXT.md # IDEs .vs/ +*.csproj.user *.DotSettings.user +# Test results +BenchmarkDotNet.Artifacts/ + # Test resources resources/ diff --git a/.gitmodules b/.gitmodules index 3f59342..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "docs/templates/material"] - path = docs/templates/material - url = https://github.com/ovasquez/docfx-material.git diff --git a/.prettierrc.yaml b/.prettierrc.yaml new file mode 100644 index 0000000..ec3b3e2 --- /dev/null +++ b/.prettierrc.yaml @@ -0,0 +1,4 @@ +overrides: + - files: "*.md" + options: + proseWrap: always diff --git a/.vscode/header-cs.code-snippets b/.vscode/header-cs.code-snippets index 3578fb3..eadbd6c 100644 --- a/.vscode/header-cs.code-snippets +++ b/.vscode/header-cs.code-snippets @@ -4,7 +4,7 @@ "prefix": "header", "description": "Insert the C# file header", "body": [ - "// Copyright (c) 2022 SceneGate", + "// Copyright (c) 2023 SceneGate", "", "// Permission is hereby granted, free of charge, to any person obtaining a copy", "// of this software and associated documentation files (the \"Software\"), to deal", diff --git a/.vscode/settings.json b/.vscode/settings.json index d81b5d5..a09439a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -12,7 +12,6 @@ "editor.defaultFormatter": "ms-dotnettools.csharp", "editor.formatOnType": true }, - "prettier.proseWrap": "always", "cSpell.words": [ "Agcb", "cref", diff --git a/.vscode/tasks.json b/.vscode/tasks.json index dbaf89d..f23f282 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -5,59 +5,32 @@ "type": "process", "command": "dotnet", "args": [ - "cake" - ], - "group": "build", - "problemMatcher": [ - "$msCompile" - ], - "label": "Cake: Run Default" - }, - { - "type": "process", - "command": "dotnet", - "args": [ - "cake", - "--target=Build" + "run", + "--project", + "build/orchestrator/", ], "group": { "kind": "build", "isDefault": true }, - "problemMatcher": [ - "$msCompile" - ], - "label": "Cake: Run Build" + "problemMatcher": ["$msCompile"], + "label": "Build" }, { "type": "process", "command": "dotnet", "args": [ - "cake", - "--target=BuildTest" + "run", + "--project", + "build/orchestrator/", + "--", + "--target=Bundle" ], "group": { - "kind": "test", - "isDefault": true + "kind": "build", }, - "problemMatcher": [ - "$msCompile" - ], - "label": "Cake: Run Test" + "problemMatcher": ["$msCompile"], + "label": "Bundle" }, - { - "type": "process", - "command": "dotnet", - "args": [ - "cake", - "--target=Build", - "--configuration=Release" - ], - "group": "build", - "problemMatcher": [ - "$msCompile" - ], - "label": "Cake: Run Build for release" - } ] -} \ No newline at end of file +} diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 0fe241e..a6d79eb 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,45 +2,73 @@ ## Our Pledge -In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of +experience, nationality, personal appearance, race, religion, or sexual identity +and orientation. ## Our Standards -Examples of behavior that contributes to creating a positive environment include: +Examples of behavior that contributes to creating a positive environment +include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities -Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. -Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. +Project maintainers have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, or to ban temporarily or permanently any +contributor for other behaviors that they deem inappropriate, threatening, +offensive, or harmful. ## Scope -This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. ## Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at benito356@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at . The project +team will review and investigate all complaints, and will respond in a way that +it deems appropriate to the circumstances. The project team is obligated to +maintain confidentiality with regard to the reporter of an incident. Further +details of specific enforcement policies may be posted separately. -Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a6037f0..80dd464 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,6 +5,10 @@ Thanks for taking the time to contribute! :sparkles: In this document you will find all the information you need to make sure that the projects continues to be consistent and with great quality! +> [!NOTE] +> By contributing in this repository you accept the +> [developer certificate of origin](https://developercertificate.org/). + ## Reporting features and issues ### Issues diff --git a/GitReleaseManager.yaml b/GitReleaseManager.yaml index 868b51c..e9506df 100644 --- a/GitReleaseManager.yaml +++ b/GitReleaseManager.yaml @@ -26,8 +26,8 @@ close: issue-labels-include: - Breaking - Bug - - Documentation - Duplicate + - Documentation - Enhancement - Feature - Improvement diff --git a/GitVersion.yml b/GitVersion.yml index 6f5e41f..d5871d6 100644 --- a/GitVersion.yml +++ b/GitVersion.yml @@ -1,6 +1,5 @@ mode: ContinuousDeployment branches: - master: - regex: ^main$ + main: tag: preview increment: Patch diff --git a/README.md b/README.md index f41beff..de2bd98 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,30 @@ -# Ekona [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://choosealicense.com/licenses/mit/) ![Build and release](https://github.com/SceneGate/Ekona/workflows/Build%20and%20release/badge.svg) +# Ekona + + +

+ + Stable version + +   + + GitHub commits since latest release (by SemVer) + +   + + Build and release + +   + + MIT License + +   +

_Ekona_ is a library part of the [_SceneGate_](https://github.com/SceneGate) -framework that provides support for DS and DSi file formats. +framework that provides support for **DS and DSi file formats.** The library supports .NET 6.0 and above on Linux, Window and MacOS. - -| Release | Package | -| ------- | ----------------------------------------------------------------- | -| Stable | [![Nuget](https://img.shields.io/nuget/v/SceneGate.Ekona?label=nuget.org&logo=nuget)](https://www.nuget.org/packages/SceneGate.Ekona) | -| Preview | [Azure Artifacts](https://dev.azure.com/SceneGate/SceneGate/_packaging?_a=feed&feed=SceneGate-Preview) | - ## Supported formats - :video_game: DS cartridge: @@ -29,7 +43,7 @@ The library supports .NET 6.0 and above on Linux, Window and MacOS. ## Getting started Check-out the -[getting started guide](https://scenegate.github.io/Ekona/dev/introduction.html) +[getting started guide](https://scenegate.github.io/Ekona/docs/dev/tutorial.html) to start using _Ekona_ in no time! Below you can find an example that shows how to open a DS/DSi ROM file (cartridge dump). @@ -85,11 +99,11 @@ your solution file (.sln) with the following content: ## Documentation You can get full details about how to use library from the -[documentation](https://scenegate.github.io/Ekona/dev/features/cartridge.html) +[documentation](https://scenegate.github.io/Ekona/docs/dev/features/cartridge.html) website. Don't miss the -[formats specifications](https://scenegate.github.io/Ekona/specs/cartridge/cartridge.html) +[formats specifications](https://scenegate.github.io/Ekona/docs/specs/cartridge/cartridge.html) in case you need to do further research. And don't hesitate to ask questions in the @@ -97,40 +111,24 @@ And don't hesitate to ask questions in the ## Build -Building requires the -[.NET 6.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/6.0) and .NET -Framework 4.8 or the latest -[Mono](https://www.mono-project.com/download/stable/). If you open the project -with VS Code and you did install the -[VS Code Remote Containers](https://code.visualstudio.com/docs/remote/containers) -extension, you can have an already pre-configured development environment with -Docker or Podman. +The project requires to build .NET 8.0 SDK. To build, test and generate artifacts run: ```sh -# Only required the first time -dotnet tool restore - -# It will build, run the tests and create the artifacts (NuGets and doc) -dotnet cake -``` +# Build and run tests +dotnet run --project build/orchestrator -To build and test only, run: - -```sh -dotnet cake --target=BuildTest +# (Optional) Create bundles (nuget, zips, docs) +dotnet run --project build/orchestrator -- --target=Bundle ``` To build the documentation only, run: ```sh -dotnet cake --target=Build-Doc +dotnet docfx docs/docfx.json --serve ``` -If any of the previous tasks fail and you want to get more verbosity, re-run the -command with the argument `--verbosity=diagnostic` - To run the performance test with memory and CPU traces: ```sh diff --git a/build.cake b/build.cake deleted file mode 100644 index 66ee8a6..0000000 --- a/build.cake +++ /dev/null @@ -1,53 +0,0 @@ -#load "nuget:?package=PleOps.Cake&version=0.7.0" - -string testResourceUri = Argument("resource-uri", string.Empty); - -Task("Define-Project") - .Description("Fill specific project information") - .Does(info => -{ - info.AddLibraryProjects("Ekona"); - info.AddTestProjects("Ekona.Tests"); - - info.PreviewNuGetFeed = "https://pkgs.dev.azure.com/SceneGate/SceneGate/_packaging/SceneGate-Preview/nuget/v3/index.json"; - - info.CoverageTarget = 85; -}); - -Task("Download-TestFiles") - .Description("Download the test resource files") - .IsDependeeOf("Test") - .Does(() => -{ - string resourcesPath = MakeAbsolute(Directory("./resources")).FullPath; - - if (DirectoryExists("resources")) { - Information("Test files already exists, skipping download."); - System.Environment.SetEnvironmentVariable("SCENEGATE_TEST_DIR", resourcesPath); - return; - } - - if (string.IsNullOrEmpty(testResourceUri)) { - Information("Test resource uri is not present, skipping download."); - return; - } - - var jsonInfoPath = DownloadFile(testResourceUri); - string jsonInfoText = System.IO.File.ReadAllText(jsonInfoPath.FullPath); - IEnumerable resources = System.Text.Json.JsonSerializer.Deserialize>(jsonInfoText); - - foreach (TestResource resource in resources) { - var compressedResources = DownloadFile(resource.uri); - Unzip(compressedResources, resource.path); - } - - System.Environment.SetEnvironmentVariable("SCENEGATE_TEST_DIR", resourcesPath); -}); - -Task("Default") - .IsDependentOn("Stage-Artifacts"); - -string target = Argument("target", "Default"); -RunTarget(target); - -private sealed record TestResource(string uri, string path); diff --git a/build/orchestrator/BuildContext.cs b/build/orchestrator/BuildContext.cs new file mode 100644 index 0000000..b05c2fe --- /dev/null +++ b/build/orchestrator/BuildContext.cs @@ -0,0 +1,21 @@ +using Cake.Core; +using Cake.Frosting.PleOps.Recipe; + +namespace BuildSystem; + +public class BuildContext : PleOpsBuildContext +{ + public BuildContext(ICakeContext context) : base(context) + { + TestResourceUri = string.Empty; + } + + public string TestResourceUri { get; set; } + + public override void ReadArguments() + { + base.ReadArguments(); + + Arguments.SetIfPresent("resource-uri", x => TestResourceUri = x); + } +} diff --git a/build/orchestrator/BuildSystem.csproj b/build/orchestrator/BuildSystem.csproj new file mode 100644 index 0000000..560a707 --- /dev/null +++ b/build/orchestrator/BuildSystem.csproj @@ -0,0 +1,17 @@ + + + + Exe + + net8.0 + $(MSBuildProjectDirectory)/../.. + + enable + enable + + + + + + + diff --git a/build/orchestrator/BuildSystem.sln b/build/orchestrator/BuildSystem.sln new file mode 100644 index 0000000..d332efc --- /dev/null +++ b/build/orchestrator/BuildSystem.sln @@ -0,0 +1,22 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31903.59 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BuildSystem", "BuildSystem.csproj", "{C3AF4C5B-294F-4EA3-BCC9-3E6B2AA4D569}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C3AF4C5B-294F-4EA3-BCC9-3E6B2AA4D569}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C3AF4C5B-294F-4EA3-BCC9-3E6B2AA4D569}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C3AF4C5B-294F-4EA3-BCC9-3E6B2AA4D569}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C3AF4C5B-294F-4EA3-BCC9-3E6B2AA4D569}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/build/orchestrator/DownloadTestFilesTask.cs b/build/orchestrator/DownloadTestFilesTask.cs new file mode 100644 index 0000000..e7c6ff9 --- /dev/null +++ b/build/orchestrator/DownloadTestFilesTask.cs @@ -0,0 +1,44 @@ +using System.Collections.ObjectModel; +using System.Text.Json; +using Cake.Common.IO; +using Cake.Common.Net; +using Cake.Core.Diagnostics; +using Cake.Frosting; + +namespace BuildSystem; + +[TaskName("Download-TestFiles")] +[TaskDescription("Download the test resource files")] +[IsDependeeOf(typeof(Cake.Frosting.PleOps.Recipe.Dotnet.TestTask))] +public class DownloadTestFilesTask : FrostingTask +{ + public override void Run(BuildContext context) + { + string resourcesPath = Path.GetFullPath("./resources"); + Environment.SetEnvironmentVariable("SCENEGATE_TEST_DIR", resourcesPath); + + if (Directory.Exists("resources")) { + context.Log.Information("Test files already exists, skipping download."); + return; + } + + if (string.IsNullOrEmpty(context.TestResourceUri)) { + context.Log.Information("Test resource uri is not present, skipping download."); + return; + } + + var jsonInfoPath = context.DownloadFile(context.TestResourceUri); + string jsonInfoText = File.ReadAllText(jsonInfoPath.FullPath); + IEnumerable? resources = JsonSerializer.Deserialize>(jsonInfoText); + if (resources is null) { + throw new Exception("Failed to read json info file"); + } + + foreach (TestResource resource in resources) { + var compressedResources = context.DownloadFile(resource.uri); + context.Unzip(compressedResources, resource.path); + } + } + + private sealed record TestResource(string uri, string path); +} diff --git a/build/orchestrator/Program.cs b/build/orchestrator/Program.cs new file mode 100644 index 0000000..92e36cc --- /dev/null +++ b/build/orchestrator/Program.cs @@ -0,0 +1,55 @@ +using BuildSystem; +using Cake.Core; +using Cake.Frosting; +using Cake.Frosting.PleOps.Recipe; + +return new CakeHost() + .AddAssembly(typeof(PleOpsBuildContext).Assembly) + .UseContext() + .UseLifetime() + .Run(args); + +public sealed class BuildLifetime : FrostingLifetime +{ + public override void Setup(BuildContext context, ISetupContext info) + { + context.DotNetContext.CoverageTarget = 85; + + context.ReadArguments(); + + context.DotNetContext.PreviewNuGetFeed = "https://pkgs.dev.azure.com/SceneGate/SceneGate/_packaging/SceneGate-Preview/nuget/v3/index.json"; + + context.Print(); + } + + public override void Teardown(BuildContext context, ITeardownContext info) + { + // Save the info from the existing artifacts for the next execution (e.g. deploy job) + context.DeliveriesContext.Save(); + } +} + +[TaskName("Default")] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.SetGitVersionTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.CleanArtifactsTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Dotnet.DotnetTasks.BuildProjectTask))] +public sealed class DefaultTask : FrostingTask +{ +} + +[TaskName("Bundle")] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.SetGitVersionTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.GitHub.ExportReleaseNotesTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Dotnet.DotnetTasks.BundleProjectTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.DocFx.BuildTask))] +public sealed class BundleTask : FrostingTask +{ +} + +[TaskName("Deploy")] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Common.SetGitVersionTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.Dotnet.DotnetTasks.DeployProjectTask))] +[IsDependentOn(typeof(Cake.Frosting.PleOps.Recipe.GitHub.UploadReleaseBinariesTask))] +public sealed class DeployTask : FrostingTask +{ +} diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..83cc63a --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,12 @@ +############### +# folder # +############### +/**/DROP/ +/**/TEMP/ +/**/packages/ +/**/bin/ +/**/obj/ +_site + +# DrawIO +.$*.drawio* diff --git a/docs/api/.gitignore b/docs/api/.gitignore new file mode 100644 index 0000000..e8079a3 --- /dev/null +++ b/docs/api/.gitignore @@ -0,0 +1,5 @@ +############### +# temp file # +############### +*.yml +.manifest diff --git a/docs/dev/Changelog.md b/docs/articles/changelog.md similarity index 100% rename from docs/dev/Changelog.md rename to docs/articles/changelog.md diff --git a/docs/dev/features/cartridge.md b/docs/articles/dev/features/cartridge.md similarity index 95% rename from docs/dev/features/cartridge.md rename to docs/articles/dev/features/cartridge.md index 5ee5892..eaf40eb 100644 --- a/docs/dev/features/cartridge.md +++ b/docs/articles/dev/features/cartridge.md @@ -27,7 +27,7 @@ format can be converted / unpacked into a tree _nodes_ with the converter > - _Parameters_: (_Optional_) > [`DsiKeyStore`](xref:SceneGate.Ekona.Security.DsiKeyStore) -[!code-csharp[OpenGame](../../../src/Ekona.Examples/QuickStart.cs?name=OpenGame)] +[!code-csharp[OpenGame](../../../../src/Ekona.Examples/QuickStart.cs?name=OpenGame)] The converter will use the following converters to transform some binary data into the specific format: @@ -81,7 +81,7 @@ into the ROM / cartridge binary format using the converter > the compressed length in the _arm9_ program with zero. Otherwise it will > set the current _arm9_ program length. -[!code-csharp[WriteGame](../../../src/Ekona.Examples/QuickStart.cs?name=WriteGame)] +[!code-csharp[WriteGame](../../../../src/Ekona.Examples/QuickStart.cs?name=WriteGame)] The converter will use the following converters to transform the program and banner information into binary data: @@ -163,7 +163,7 @@ so. You can decrypt or encrypt the file later by using the class [`NitroKey1Encryption`](xref:SceneGate.Ekona.Security.NitroKey1Encryption) -[!code-csharp[DecryptEncryptArm9](../../../src/Ekona.Examples/Cartridge.cs?name=DecryptEncryptArm9)] +[!code-csharp[DecryptEncryptArm9](../../../../src/Ekona.Examples/Cartridge.cs?name=DecryptEncryptArm9)] ## Animated icon @@ -184,7 +184,7 @@ type from _Texim_. You can use later its converters to convert to GIF format. > - _Output format_: `AnimatedFullImage` > - _Parameters_: none -[!code-csharp[ExportIconGif](../../../src/Ekona.Examples/Cartridge.cs?name=ExportIconGif)] +[!code-csharp[ExportIconGif](../../../../src/Ekona.Examples/Cartridge.cs?name=ExportIconGif)] > [!NOTE] > It is not possible to import the icon from a GIF file, only export. If you diff --git a/docs/articles/dev/toc.yml b/docs/articles/dev/toc.yml new file mode 100644 index 0000000..08598e9 --- /dev/null +++ b/docs/articles/dev/toc.yml @@ -0,0 +1,13 @@ +- name: ✨ Getting started +- name: Introduction + href: ../../index.md +- name: Getting started guide + href: tutorial.md + +- name: ♻️ Converters +- name: Cartridge + href: features/cartridge.md + +- name: 📃 API docs +- name: Namespaces + href: ../../api/toc.yml diff --git a/docs/dev/introduction.md b/docs/articles/dev/tutorial.md similarity index 72% rename from docs/dev/introduction.md rename to docs/articles/dev/tutorial.md index a7ea921..7b43d9c 100644 --- a/docs/dev/introduction.md +++ b/docs/articles/dev/tutorial.md @@ -1,7 +1,7 @@ -# _Ekona: DS and DSi formats_ +# Getting started guide -_Ekona_ is a library part of the _SceneGate_ framework that provides support for -DS and DSi file formats. +Welcome to _Ekona_, a library part of the _SceneGate_ framework that provides +support for DS and DSi file formats. ## Usage @@ -21,7 +21,7 @@ _unpack_ the ROM by using the converter [`Binar2NitroRom`](xref:SceneGate.Ekona.Containers.Rom.Binary2NitroRom). It will create a tree of _nodes_ that we can use to access to the files. -[!code-csharp[OpenGame](../../src/Ekona.Examples/QuickStart.cs?name=OpenGame)] +[!code-csharp[OpenGame](../../../src/Ekona.Examples/QuickStart.cs?name=OpenGame)] > [!NOTE] > The converter will not write any file to the disk. It will create a tree of @@ -30,13 +30,13 @@ create a tree of _nodes_ that we can use to access to the files. Now we can quickly modify our file even by code! -[!code-csharp[ModifyFile](../../src/Ekona.Examples/QuickStart.cs?name=ModifyFile)] +[!code-csharp[ModifyFile](../../../src/Ekona.Examples/QuickStart.cs?name=ModifyFile)] Finally, to generate a new game (ROM) file we just need one more line of code to use the [`NitroRom2Binary`](xref:SceneGate.Ekona.Containers.Rom.NitroRom2Binary) converter. -[!code-csharp[WriteGame](../../src/Ekona.Examples/QuickStart.cs?name=WriteGame)] +[!code-csharp[WriteGame](../../../src/Ekona.Examples/QuickStart.cs?name=WriteGame)] > [!TIP] > Check-out the [cartridge](features/cartridge.md) section to learn about the @@ -47,14 +47,14 @@ converter. Once we have opened a game, we can access to all the information from its header easily via the `system/info` node. -[!code-csharp[HeaderInfo](../../src/Ekona.Examples/QuickStart.cs?name=HeaderInfo)] +[!code-csharp[HeaderInfo](../../../src/Ekona.Examples/QuickStart.cs?name=HeaderInfo)] In a similar way, you can access to the information from the banner like the game title in different languages: -[!code-csharp[BannerTitle](../../src/Ekona.Examples/QuickStart.cs?name=BannerTitle)] +[!code-csharp[BannerTitle](../../../src/Ekona.Examples/QuickStart.cs?name=BannerTitle)] You can also export the game icon. If it's a DSi game, it may even have an animated icon that you can export as GIF! -[!code-csharp[ExportIcon](../../src/Ekona.Examples/QuickStart.cs?name=ExportIcon)] +[!code-csharp[ExportIcon](../../../src/Ekona.Examples/QuickStart.cs?name=ExportIcon)] diff --git a/docs/specs/cartridge/banner.md b/docs/articles/specs/cartridge/banner.md similarity index 100% rename from docs/specs/cartridge/banner.md rename to docs/articles/specs/cartridge/banner.md diff --git a/docs/specs/cartridge/cartridge.md b/docs/articles/specs/cartridge/cartridge.md similarity index 100% rename from docs/specs/cartridge/cartridge.md rename to docs/articles/specs/cartridge/cartridge.md diff --git a/docs/specs/cartridge/filesystem.md b/docs/articles/specs/cartridge/filesystem.md similarity index 100% rename from docs/specs/cartridge/filesystem.md rename to docs/articles/specs/cartridge/filesystem.md diff --git a/docs/specs/cartridge/header.md b/docs/articles/specs/cartridge/header.md similarity index 100% rename from docs/specs/cartridge/header.md rename to docs/articles/specs/cartridge/header.md diff --git a/docs/specs/cartridge/program.md b/docs/articles/specs/cartridge/program.md similarity index 97% rename from docs/specs/cartridge/program.md rename to docs/articles/specs/cartridge/program.md index 077be23..d317119 100644 --- a/docs/specs/cartridge/program.md +++ b/docs/articles/specs/cartridge/program.md @@ -1,164 +1,164 @@ -# Cartridge programs - -The DS and DSi have two processors: ARM9 and ARM7. Each processor loads a -different program and run it in parallel. The hardware contains synchronization -mechanism between the two processors and there is an area of the RAM that it's -shared between the two processors. - -The developers usually only can write code for the ARM9 processor. The ARM7 -processor is reserved for the system code like controlling the hardware (sound, -touchscreen). The compiled object files with the assembly code are usually named -after the processors: `arm9.bin` and `arm7.bin`. - -DSi-enhanced and exclusive games contain two additional programs for the same -processors. These files contains DSi exclusive code that it's only load when the -game runs on a DSi console. These files are load into a different RAM address -and are called from the regular program file. It allows to run the program on -regular DS consoles with additional features when it runs in DSi consoles. These -files are usually named `arm9i.bin` and `arm7i.bin`. - -The header of the cartridge contains several fields for these files including: - -- File offset -- File length -- Load address into the RAM -- Entry point (first line of code to execute) -- [Program parameters](#program-parameters) - -## Overlays - -The RAM memory of the DS devices is very limited and it needs to hold the -program and its data. To save memory, large code program files are usually split -by features into different files (similar to the concept of libraries). These -files are named _overlays_ and can be load and unload from memory at any moment -from the main (_armX.bin_) program. For instance, some games put all its code -for battles on an separate overlay. This overlay is loaded into memory when the -battle starts and removed when it finishes. Different overlays may be load into -the same RAM address but at different times. - -Practically speaking, programs only contain overlays for the ARM9 processor. - -### Overlay information table - -Before the data of each overlay file, there is a table that contains a set of -fields for each overlay. For each overlay there are 32-bytes as follow: - -| Offset | Format | Description | -| ------ | ------ | ----------------------------------- | -| 0x00 | uint | ID | -| 0x04 | uint | Load RAM address | -| 0x08 | uint | File length to load into RAM | -| 0x0C | uint | BSS data section length | -| 0x10 | uint | Static initialization start address | -| 0x14 | uint | Static initialization end address | -| 0x18 | uint | Overlay file ID (same as [0x00]) | -| 0x1C | uint | Flags | - -Flags: - -| Bits | Description | -| ----- | ------------------------------------------- | -| 0-23 | Compressed file length (0 for uncompressed) | -| 24 | If set, the file is compressed | -| 25 | If set, the overlay is digitally signed | -| 26-31 | Reserved | - -## Secure area - -The first 16 KB of the ARM9 program code lands into the _secure area_ section of -the ROM. These bytes must be load using a special command of the cartridge -protocol. Additionally the first 2 KB of the _secure area_ (so of the file) are -_KEY1_ encrypted. - -The first 2 KB doesn't usually contain code. Instead its format is: - -| Offset | Format | Description | -| ------ | ----------- | --------------------------------------------- | -| 0x00 | char[8] | Encryption token `encryObj` | -| 0x08 | uint | Constant `FF DE FF E7 FF DE` | -| 0x0E | ushort | CRC-16 of the next 0x7F0 bytes. | -| 0x10 | byte[0x7F0] | Garbage / random bytes with small code blocks | - -The console decrypts first the initial 8 bytes. If the result does not match -`encryObj`, then it assumes the content is wrong and corrupts the rest of the -data with the same bytes as the token. If the data match, then overwrites these -characters with `FF DE FF E7 FF DE FF E7` (to hide the token). - -The BIOS nor the firmware do not verify the CRC-16. They only verify the first -8-bytes with the token. For this reason, this area is usually used for hooks and -patch code. - -### Disable secure area - -The secure area can be disabled by setting a special constant value in the -cartridge header at 0x78. The constant is encrypted with -[KEY1](security.md#blowfish-key1) encryption. It's decrypted value is -`NmMdOnly`. - -## Program parameters - -The ARM9 program contains a table inside the file that defines additional -parameters about the format like the location of _ITCM_ code or the -[_BSS_](https://en.wikipedia.org/wiki/.bss) area. These parameters are used at -runtime to initialize the program before calling the actual program entry-point. - -The location of this table is defined in the extended header for DSi games. In -the case of DS games, there are 12 bytes after the ARM9 program file (also known -as _arm9 tail_) that defines additional pointers. These bytes are not included -as part of the length of the ARM9 program file. The format of these bytes is: - -| Offset | Format | Description | -| ------ | ------ | ----------------------------------------------------- | -| 0x00 | uint | Constant: `0x2106C0DE` (_nitrocode_ marker) | -| 0x04 | uint | Offset to table parameters (see below) | -| 0x08 | uint | Offset to [HMAC-SHA1 table for overlays](security.md) | - -If the _nitrocode_ marker is present, then this structure exists. This constant -or marker is used across the _arm9_ program code to identify structures of data -after the compilation phase. - -> [!TIP] -> The constant number is a play of hexadecimal numbers to create the word: -> _nitro code_. _Nitro_ was the project name of the DS device. The meaning of -> the bytes is: -> -> - `2`: _ni_ japanese number -> - `10`: _to_ japanese number -> - `6`: _ro_ japanese number -> - `C0DE`: _code_ with hexadecimal numbers - -The format of the program parameter table is: - -| Offset | Format | Description | -| ------ | -------- | ----------------------------------------------------- | -| 0x00 | uint | First ITCM block info | -| 0x04 | uint | Last ITCM block info | -| 0x08 | uint | ITCM data offset | -| 0x0C | uint | BSS data offset | -| 0x10 | uint | BSS data end offset | -| 0x14 | uint | Compressed program size | -| 0x18 | uint | SDK version with format: major.minor.build | -| 0x1C | uint | _nitrocode_ marker | -| 0x20 | uint | _nitrocode_ marker in big endian | -| 0x24 | string[] | Frameworks used with format `[:]` | - -An _ITCM block info_ consists of two 32-bits integer values: target RAM address -and block size. The data should be copied consecutive starting from _ITCM data -offset_ field value. - -> [!NOTE] -> Programs regenerating a cartridge file should take into account the -> _compressed program size_ field value and update it if the _program file_ -> changes and it's compressed value is different. - -## Program entrypoint - -The entrypoint code for the _ARM9_ program is defined by the SDK. It runs a set -of initialization steps before calling the actual program _main_ function. - -These initializations includes: - -- Set the program stack address -- Moves program code and data to TCM areas (cache areas that run faster) -- Clean the _BSS_ area -- Decompress the rest of the program file (reverse LZSS compression or BLZ) +# Cartridge programs + +The DS and DSi have two processors: ARM9 and ARM7. Each processor loads a +different program and run it in parallel. The hardware contains synchronization +mechanism between the two processors and there is an area of the RAM that it's +shared between the two processors. + +The developers usually only can write code for the ARM9 processor. The ARM7 +processor is reserved for the system code like controlling the hardware (sound, +touchscreen). The compiled object files with the assembly code are usually named +after the processors: `arm9.bin` and `arm7.bin`. + +DSi-enhanced and exclusive games contain two additional programs for the same +processors. These files contains DSi exclusive code that it's only load when the +game runs on a DSi console. These files are load into a different RAM address +and are called from the regular program file. It allows to run the program on +regular DS consoles with additional features when it runs in DSi consoles. These +files are usually named `arm9i.bin` and `arm7i.bin`. + +The header of the cartridge contains several fields for these files including: + +- File offset +- File length +- Load address into the RAM +- Entry point (first line of code to execute) +- [Program parameters](#program-parameters) + +## Overlays + +The RAM memory of the DS devices is very limited and it needs to hold the +program and its data. To save memory, large code program files are usually split +by features into different files (similar to the concept of libraries). These +files are named _overlays_ and can be load and unload from memory at any moment +from the main (_armX.bin_) program. For instance, some games put all its code +for battles on an separate overlay. This overlay is loaded into memory when the +battle starts and removed when it finishes. Different overlays may be load into +the same RAM address but at different times. + +Practically speaking, programs only contain overlays for the ARM9 processor. + +### Overlay information table + +Before the data of each overlay file, there is a table that contains a set of +fields for each overlay. For each overlay there are 32-bytes as follow: + +| Offset | Format | Description | +| ------ | ------ | ----------------------------------- | +| 0x00 | uint | ID | +| 0x04 | uint | Load RAM address | +| 0x08 | uint | File length to load into RAM | +| 0x0C | uint | BSS data section length | +| 0x10 | uint | Static initialization start address | +| 0x14 | uint | Static initialization end address | +| 0x18 | uint | Overlay file ID (same as [0x00]) | +| 0x1C | uint | Flags | + +Flags: + +| Bits | Description | +| ----- | ------------------------------------------- | +| 0-23 | Compressed file length (0 for uncompressed) | +| 24 | If set, the file is compressed | +| 25 | If set, the overlay is digitally signed | +| 26-31 | Reserved | + +## Secure area + +The first 16 KB of the ARM9 program code lands into the _secure area_ section of +the ROM. These bytes must be load using a special command of the cartridge +protocol. Additionally the first 2 KB of the _secure area_ (so of the file) are +_KEY1_ encrypted. + +The first 2 KB doesn't usually contain code. Instead its format is: + +| Offset | Format | Description | +| ------ | ----------- | --------------------------------------------- | +| 0x00 | char[8] | Encryption token `encryObj` | +| 0x08 | uint | Constant `FF DE FF E7 FF DE` | +| 0x0E | ushort | CRC-16 of the next 0x7F0 bytes. | +| 0x10 | byte[0x7F0] | Garbage / random bytes with small code blocks | + +The console decrypts first the initial 8 bytes. If the result does not match +`encryObj`, then it assumes the content is wrong and corrupts the rest of the +data with the same bytes as the token. If the data match, then overwrites these +characters with `FF DE FF E7 FF DE FF E7` (to hide the token). + +The BIOS nor the firmware do not verify the CRC-16. They only verify the first +8-bytes with the token. For this reason, this area is usually used for hooks and +patch code. + +### Disable secure area + +The secure area can be disabled by setting a special constant value in the +cartridge header at 0x78. The constant is encrypted with +[KEY1](security.md#blowfish-key1) encryption. It's decrypted value is +`NmMdOnly`. + +## Program parameters + +The ARM9 program contains a table inside the file that defines additional +parameters about the format like the location of _ITCM_ code or the +[_BSS_](https://en.wikipedia.org/wiki/.bss) area. These parameters are used at +runtime to initialize the program before calling the actual program entry-point. + +The location of this table is defined in the extended header for DSi games. In +the case of DS games, there are 12 bytes after the ARM9 program file (also known +as _arm9 tail_) that defines additional pointers. These bytes are not included +as part of the length of the ARM9 program file. The format of these bytes is: + +| Offset | Format | Description | +| ------ | ------ | ----------------------------------------------------- | +| 0x00 | uint | Constant: `0x2106C0DE` (_nitrocode_ marker) | +| 0x04 | uint | Offset to table parameters (see below) | +| 0x08 | uint | Offset to [HMAC-SHA1 table for overlays](security.md) | + +If the _nitrocode_ marker is present, then this structure exists. This constant +or marker is used across the _arm9_ program code to identify structures of data +after the compilation phase. + +> [!TIP] +> The constant number is a play of hexadecimal numbers to create the word: +> _nitro code_. _Nitro_ was the project name of the DS device. The meaning of +> the bytes is: +> +> - `2`: _ni_ japanese number +> - `10`: _to_ japanese number +> - `6`: _ro_ japanese number +> - `C0DE`: _code_ with hexadecimal numbers + +The format of the program parameter table is: + +| Offset | Format | Description | +| ------ | -------- | ----------------------------------------------------- | +| 0x00 | uint | First ITCM block info | +| 0x04 | uint | Last ITCM block info | +| 0x08 | uint | ITCM data offset | +| 0x0C | uint | BSS data offset | +| 0x10 | uint | BSS data end offset | +| 0x14 | uint | Compressed program size | +| 0x18 | uint | SDK version with format: major.minor.build | +| 0x1C | uint | _nitrocode_ marker | +| 0x20 | uint | _nitrocode_ marker in big endian | +| 0x24 | string[] | Frameworks used with format `[:]` | + +An _ITCM block info_ consists of two 32-bits integer values: target RAM address +and block size. The data should be copied consecutive starting from _ITCM data +offset_ field value. + +> [!NOTE] +> Programs regenerating a cartridge file should take into account the +> _compressed program size_ field value and update it if the _program file_ +> changes and it's compressed value is different. + +## Program entrypoint + +The entrypoint code for the _ARM9_ program is defined by the SDK. It runs a set +of initialization steps before calling the actual program _main_ function. + +These initializations includes: + +- Set the program stack address +- Moves program code and data to TCM areas (cache areas that run faster) +- Clean the _BSS_ area +- Decompress the rest of the program file (reverse LZSS compression or BLZ) diff --git a/docs/specs/cartridge/security.md b/docs/articles/specs/cartridge/security.md similarity index 100% rename from docs/specs/cartridge/security.md rename to docs/articles/specs/cartridge/security.md diff --git a/docs/articles/specs/toc.yml b/docs/articles/specs/toc.yml new file mode 100644 index 0000000..58512f0 --- /dev/null +++ b/docs/articles/specs/toc.yml @@ -0,0 +1,13 @@ +- name: 📁 Cartridge +- name: Cartridge + href: cartridge/cartridge.md +- name: Header + href: cartridge/header.md +- name: File system + href: cartridge/filesystem.md +- name: Banner + href: cartridge/banner.md +- name: Programs (armX) + href: cartridge/program.md +- name: Security + href: cartridge/security.md diff --git a/docs/dev/Contributing.md b/docs/dev/Contributing.md deleted file mode 100644 index 00bde09..0000000 --- a/docs/dev/Contributing.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -uid: CONTRIBUTING ---- - -[!include[CONTRIBUTING](../../CONTRIBUTING.md)] diff --git a/docs/dev/toc.yml b/docs/dev/toc.yml deleted file mode 100644 index 545c527..0000000 --- a/docs/dev/toc.yml +++ /dev/null @@ -1,18 +0,0 @@ -- name: ✨ Getting started - href: introduction.md - -- name: ♻️ Converters - items: - - name: Cartridge - href: features/cartridge.md - -- name: API - href: ../api/toc.yml - -- name: ⌨ Contribute - items: - - name: Guidelines - href: Contributing.md - -- name: Changelog - href: Changelog.md diff --git a/docs/docfx.json b/docs/docfx.json index e026194..072b112 100644 --- a/docs/docfx.json +++ b/docs/docfx.json @@ -1,49 +1,66 @@ { - "metadata": [ - { - "src": [ - { - "files": [ - "Ekona/bin/**/SceneGate.Ekona.dll" - ], - "src": "../src" - } - ], - "dest": "api", - "filter": "filter_config.yml", - "disableGitFeatures": false, - "disableDefaultFilter": false - } - ], - "build": { - "content": [ - { "files": [ "api/**.yml", "dev/**" ] }, - { "files": [ "specs/**" ] }, - { "files": [ "toc.yml", "index.md" ] }, + "metadata": [ + { + "src": [ { - "files": [ "README.md", "CONTRIBUTING.md" ], - "src": "../" + "files": [ + "Ekona/*.csproj" + ], + "src": "../src" } ], - "resource": [ - { "files": [ "images/**" ] }, - { "files": [ "Ekona.Examples/**.cs" ], "src": "../src" } - ], - "dest": "_site", - "globalMetadataFiles": [ "global_metadata.json" ], - "fileMetadataFiles": [], - "template": [ - "default", - "statictoc", - "templates/material/material", - "templates/widescreen" - ], - "postProcessors": [ "ExtractSearchIndex" ], - "markdownEngineName": "markdig", - "noLangKeyword": false, - "keepFileLink": false, - "cleanupCacheHistory": false, + "dest": "api", + "includePrivateMembers": false, "disableGitFeatures": false, - "xrefService": [ "https://xref.docs.microsoft.com/query?uid={uid}" ] + "disableDefaultFilter": false, + "noRestore": false, + "namespaceLayout": "flattened", + "memberLayout": "samePage", + "EnumSortOrder": "alphabetic", + "allowCompilationErrors": false + } + ], + "build": { + "content": [ + { + "files": [ + "api/**.yml", + "api/index.md" + ] + }, + { "files": "**/*.{md,yml}", "src": "articles", "dest": "docs" }, + { "files": [ "toc.yml", "*.md" ] } + ], + "resource": [ + { + "files": [ "**/images/**", "**/resources/**" ], + "exclude": [ "_site/**", "obj/**" ] + } + ], + "output": "_site", + "globalMetadata": { + "_appTitle": "Ekona, SceneGate library for DS and DSi formats", + "_appName": "Ekona", + "_appFooter": "Copyright © 2021 SceneGate.
Generated by DocFX using Material (Oscar Vásquez) and Mathew (Mathew Sachin) templates.
", + "_appLogoPath": "images/logo_48.png", + "_appFaviconPath": "images/favicon.png", + "_enableSearch": true, + "_enableNewTab": true, + "_lang": "en" + }, + "fileMetadataFiles": [], + "template": [ + "default", + "modern", + "template" + ], + "postProcessors": [], + "keepFileLink": false, + "disableGitFeatures": false, + "sitemap": { + "baseUrl": "https://scenegate.github.io/Ekona/", + "priority": 0.5, + "changefreq": "monthly" } + } } diff --git a/docs/filter_config.yml b/docs/filter_config.yml deleted file mode 100644 index 4d53c6a..0000000 --- a/docs/filter_config.yml +++ /dev/null @@ -1,5 +0,0 @@ -apiRules: - # Remove object method inheritance - - exclude: - uidRegex: ^System\.Object -type: Type \ No newline at end of file diff --git a/docs/global_metadata.json b/docs/global_metadata.json deleted file mode 100644 index be9798b..0000000 --- a/docs/global_metadata.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_appTitle": "Ekona, SceneGate library for DS and DSi formats", - "_appFooter": "Copyright © 2021 SceneGate.
Generated by DocFX using Material (Oscar Vásquez) and Mathew (Mathew Sachin) templates.
", - "_appLogoPath": "images/logo_48.png", - "_appFaviconPath": "images/favicon.png", - "_enableSearch": true, - "_enableNewTab": true, - "_gitContribute": { - "apiSpecFolder": "docs/apidoc", - "repo": "https://github.com/SceneGate/Ekona", - "branch": "main" - } -} \ No newline at end of file diff --git a/docs/index.md b/docs/index.md index d1950d1..03668b1 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,5 +1,56 @@ ---- -uid: README ---- +# Ekona [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat)](https://choosealicense.com/licenses/mit/) -[!include[README](../README.md)] +_Ekona_ is a library part of the [_SceneGate_](https://github.com/SceneGate) +framework that provides support for DS and DSi file formats. + +## Supported formats + +- :video_game: DS cartridge: + - :file_folder: Filesystem: read and write + - :information_source: Header: read and write, including extended header + - :framed_picture: Banner and icon: read and write. + - :closed_lock_with_key: ARM9 secure area encryption and decryption (KEY1). +- :video_game: DSi cartridge: + - :file_folder: Filesystem: read and write `arm9i` and `arm7i` programs. + - :information_source: Extended header: read and write + - :framed_picture: Animated banner icons + - :closed_lock_with_key: Modcrypt encryption and decryption + - :lock_with_ink_pen: HMAC validation and generation when keys are provided. + - :lock_with_ink_pen: Signature validation when keys are provided. + +## Getting started + +Check-out the +[getting started guide](https://scenegate.github.io/Ekona/dev/introduction.html) +to start using _Ekona_ in no time! Below you can find an example that shows how +to open a DS/DSi ROM file (cartridge dump). + +```csharp +// Create Yarhl node from a file (binary format). +Node game = NodeFactory.FromFile("game.nds", FileOpenMode.Read); + +// Use the `Binary2NitroRom` converter to convert the binary format +// into node containers (virtual file system tree with files and directories). +game.TransformWith(); + +// And it's done! +// Now we can access to every game file. For instance, we can export one file +Node items = Navigator.SearchNode(game, "data/Items.dat"); +items.Stream.WriteTo("dump/Items.dat"); +``` + +## Usage + +The project provides the following .NET libraries (NuGet packages in nuget.org). +The libraries only support the latest .NET LTS version: **.NET 6.0**. + +- [![SceneGate.Ekona](https://img.shields.io/nuget/v/SceneGate.Ekona?label=SceneGate.Ekona&logo=nuget)](https://www.nuget.org/packages/SceneGate.Ekona) + - `SceneGate.Ekona.Containers.Rom`: DS and DSi cartridge (ROM) format. + - `SceneGate.Ekona.Security`: hash and encryption algorithms + +## Special thanks + +The DS / DSi cartridge format was based on the amazing reverse engineering work +of Martin Korth at [GBATek](https://problemkaputt.de/gbatek.htm). Its +specifications of the hardware of the video controller and I/O ports was also a +great help in additional reverse engineering. diff --git a/docs/specs/cartridge/toc.yml b/docs/specs/cartridge/toc.yml deleted file mode 100644 index 12ab7db..0000000 --- a/docs/specs/cartridge/toc.yml +++ /dev/null @@ -1,17 +0,0 @@ -- name: Cartridge - href: cartridge.md - -- name: Header - href: header.md - -- name: File system - href: filesystem.md - -- name: Banner - href: banner.md - -- name: Programs (armX) - href: program.md - -- name: Security - href: security.md diff --git a/docs/specs/toc.yml b/docs/specs/toc.yml deleted file mode 100644 index eb09058..0000000 --- a/docs/specs/toc.yml +++ /dev/null @@ -1,2 +0,0 @@ -- name: 📁 Cartridge - href: cartridge/toc.yml diff --git a/docs/template/public/main.css b/docs/template/public/main.css new file mode 100644 index 0000000..d262f7e --- /dev/null +++ b/docs/template/public/main.css @@ -0,0 +1,33 @@ +/* Changing the site font */ +@import url("https://fonts.googleapis.com/css2?family=Nunito:wght@100;400;700&display=swap"); +@import url("https://fonts.googleapis.com/css2?family=Fira Code&display=swap"); + +:root { + --bs-font-sans-serif: "Nunito"; + --bs-font-monospace: "Fira Code"; +} + +/* Hide breadcrum bar on large screen as it only links to itself */ +@media (min-width: 768px) { + .actionbar { + display: none !important; + } +} + +/* Give more space for section separation in a doc */ +h2 { + margin-top: 2rem !important; +} + +/* Improve TOC with a line for categories (entries without link) */ +.toc span.name-only { + border-bottom-color: var(--bs-tertiary-color) !important; + border-bottom-width: 2px !important; + border-bottom-style: solid !important; + margin-bottom: 0 !important; + margin-top: 0.6rem !important; +} + +.toc span.name-only:first() { + margin-top: 0.4rem !important; +} diff --git a/docs/template/public/main.js b/docs/template/public/main.js new file mode 100644 index 0000000..1d0d8c9 --- /dev/null +++ b/docs/template/public/main.js @@ -0,0 +1,9 @@ +export default { + iconLinks: [ + { + icon: "github", + href: "https://github.com/SceneGate/Ekona", + title: "GitHub", + }, + ], + }; diff --git a/docs/templates/material b/docs/templates/material deleted file mode 160000 index 2cc98b1..0000000 --- a/docs/templates/material +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 2cc98b18b70bcb5f7639269c58ab1e148eb12415 diff --git a/docs/templates/widescreen/styles/main.js b/docs/templates/widescreen/styles/main.js deleted file mode 100644 index d29bb2e..0000000 --- a/docs/templates/widescreen/styles/main.js +++ /dev/null @@ -1,4 +0,0 @@ -// From https://github.com/MathewSachin/docfx-tmpl by Mathew Sachin -var containers = $(".container"); -containers.removeClass("container"); -containers.addClass("container-fluid"); diff --git a/docs/toc.yml b/docs/toc.yml index 515fa1c..b2c7086 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -1,14 +1,11 @@ -- name: Home - href: index.md +- name: Dev guides + href: articles/dev/ -- name: Getting started - href: dev/introduction.md +- name: Format specs + href: articles/specs/ -- name: Dev docs - href: dev/features/cartridge.md - -- name: Format specifications - href: specs/ +- name: Changelog + href: articles/changelog.md - name: GitHub href: https://github.com/SceneGate/Ekona diff --git a/src/Directory.Build.props b/src/Directory.Build.props index bad6068..056fafb 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -6,43 +6,50 @@ Copyright (C) 2021 SceneGate true - NETSDK1179 + + + false MIT - https://github.com/SceneGate/Ekona + https://scenegate.github.io/Ekona/ https://github.com/SceneGate/Ekona - + icon.png README.md reverse-engineering;scenegate;nds - + true - true - snupkg + + true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + embedded + + true true - - - true true + latest true - - diff --git a/src/Directory.Packages.props b/src/Directory.Packages.props index d6b60fb..cb46396 100644 --- a/src/Directory.Packages.props +++ b/src/Directory.Packages.props @@ -15,10 +15,6 @@ - - - - diff --git a/src/Ekona.Examples/Ekona.Examples.csproj b/src/Ekona.Examples/Ekona.Examples.csproj index bdc1dd9..1f855f1 100644 --- a/src/Ekona.Examples/Ekona.Examples.csproj +++ b/src/Ekona.Examples/Ekona.Examples.csproj @@ -2,10 +2,12 @@ SceneGate.Ekona.Examples - SceneGate.Ekona.Examples Examples for the documentation. + net6.0 + SceneGate.Ekona.Examples + false enable disable diff --git a/src/Ekona.PerformanceTests/Ekona.PerformanceTests.csproj b/src/Ekona.PerformanceTests/Ekona.PerformanceTests.csproj index 2ad1b81..8d04e7f 100644 --- a/src/Ekona.PerformanceTests/Ekona.PerformanceTests.csproj +++ b/src/Ekona.PerformanceTests/Ekona.PerformanceTests.csproj @@ -3,9 +3,12 @@ Exe Ekona.PerformanceTests - SceneGate.Ekona.PerformanceTests Tests for Ekona. + net6.0 + + SceneGate.Ekona.PerformanceTests + false enable enable diff --git a/src/Ekona.Tests/Ekona.Tests.csproj b/src/Ekona.Tests/Ekona.Tests.csproj index fc09561..8a904b2 100644 --- a/src/Ekona.Tests/Ekona.Tests.csproj +++ b/src/Ekona.Tests/Ekona.Tests.csproj @@ -2,9 +2,13 @@ SceneGate.Ekona.Tests - SceneGate.Ekona.Tests Tests for Ekona. + net6.0 + + SceneGate.Ekona.Tests + false + disable diff --git a/src/Ekona/Ekona.csproj b/src/Ekona/Ekona.csproj index 62f200e..a22cfd4 100644 --- a/src/Ekona/Ekona.csproj +++ b/src/Ekona/Ekona.csproj @@ -2,13 +2,18 @@ SceneGate.Ekona - SceneGate.Ekona Library for NDS file formats. + true + net6.0 + + SceneGate.Ekona + disable - + + diff --git a/src/Tests.runsettings b/src/Tests.runsettings index 7e21d83..819918e 100644 --- a/src/Tests.runsettings +++ b/src/Tests.runsettings @@ -1,10 +1,5 @@  - - - ./../artifacts/test_results - -