NuGet Pack (#15)

This commit is contained in:
Patrick Stevens
2023-12-27 22:47:35 +00:00
committed by GitHub
parent c4bfd5eedb
commit f1304df21d
11 changed files with 239 additions and 188 deletions

View File

@@ -7,6 +7,12 @@
"commands": [ "commands": [
"fantomas" "fantomas"
] ]
},
"fsharp-analyzers": {
"version": "0.22.0",
"commands": [
"fsharp-analyzers"
]
} }
} }
} }

View File

@@ -39,6 +39,25 @@ jobs:
- name: Test - name: Test
run: nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}} run: nix develop --command dotnet test --no-build --verbosity normal --configuration ${{matrix.config}}
analyzers:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Nix
uses: cachix/install-nix-action@v24
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Prepare analyzers
run: nix develop --command dotnet restore analyzers/analyzers.fsproj
- name: Run analyzers
run: nix run .#fsharp-analyzers -- --project ./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj --analyzers-path ./.analyzerpackages/g-research.fsharp.analyzers/0.6.0/ --verbosity detailed --report ./analysis.sarif --treat-as-error GRA-STRING-001 GRA-STRING-002 GRA-STRING-003 GRA-UNIONCASE-001 GRA-INTERPOLATED-001 GRA-TYPE-ANNOTATE-001 GRA-VIRTUALCALL-001 GRA-IMMUTABLECOLLECTIONEQUALITY-001 GRA-JSONOPTS-001 GRA-LOGARGFUNCFULLAPP-001
- name: Upload SARIF file
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: analysis.sarif
build-nix: build-nix:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
@@ -89,7 +108,7 @@ jobs:
extra_nix_config: | extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }} access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Run link checker - name: Run link checker
run: nix develop --command markdown-link-check README.md run: nix develop --command markdown-link-check README.md CONTRIBUTING.md
flake-check: flake-check:
name: Check flake name: Check flake
@@ -104,8 +123,43 @@ jobs:
- name: Flake check - name: Flake check
run: nix flake check run: nix flake check
nuget-pack:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # so that NerdBank.GitVersioning has access to history
- name: Install Nix
uses: cachix/install-nix-action@v24
with:
extra_nix_config: |
access-tokens = github.com=${{ secrets.GITHUB_TOKEN }}
- name: Restore dependencies
run: nix develop --command dotnet restore
- name: Build
run: nix develop --command dotnet build --no-restore --configuration Release
- name: Pack
run: nix develop --command dotnet pack --configuration Release
- name: Upload NuGet artifact
uses: actions/upload-artifact@v4
with:
name: nuget-package
path: WoofWare.Myriad.Plugins/bin/Release/WoofWare.Myriad.Plugins.*.nupkg
expected-pack:
needs: [nuget-pack]
runs-on: ubuntu-latest
steps:
- name: Download NuGet artifact
uses: actions/download-artifact@v4
with:
name: nuget-package
- name: Check NuGet contents
# Verify that there is exactly one nupkg in the artifact that would be NuGet published
run: if [[ $(find . -maxdepth 1 -name 'WoofWare.Myriad.Plugins.*.nupkg' -printf c | wc -c) -ne "1" ]]; then exit 1; fi
all-required-checks-complete: all-required-checks-complete:
needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck, flake-check] needs: [check-dotnet-format, check-nix-format, build, build-nix, linkcheck, flake-check, analyzers, nuget-pack, expected-pack]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- run: echo "All required checks complete." - run: echo "All required checks complete."

2
.gitignore vendored
View File

@@ -7,3 +7,5 @@ riderModule.iml
*.sln.DotSettings.user *.sln.DotSettings.user
.DS_Store .DS_Store
result result
.analyzerpackages/
analysis.sarif

55
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,55 @@
# Contributing
The main project fork lives [on GitHub](https://github.com/Smaug123/WoofWare.Myriad).
Contributions are welcome, but I am generally very opinionated about both style and content.
I also can't commit to looking at anything in a particularly timely manner (or at all, though I expect I will try).
In general my aesthetics lead me to accept correctness fixes much more readily than other changes.
## Issues
Please raise bug reports and feature requests as Issues on [the main GitHub project](https://github.com/Smaug123/WoofWare.Myriad/issues).
## Pull requests
Before embarking on a large change, I strongly recommend checking via a GitHub Issue first that I'm likely to accept it.
You may find that the following guidelines will help you produce a change that I accept:
* Keep your change as small and focused as is practical.
* Ensure that your change is thoroughly tested.
* Document any choices you make which are not immediately obvious.
* Explain why your change is necessary or desirable.
## On your first checkout
There are pull request checks on this repo, enforcing [Fantomas](https://github.com/fsprojects/fantomas/)-compliant formatting according to the [G-Research style guidelines](https://github.com/G-Research/fsharp-formatting-conventions/).
After checking out the repo, you may wish to add a pre-push hook to ensure locally that formatting is complete, rather than having to wait for the CI checks to tell you that you haven't formatted your code.
Consider performing the following command to set this up in the repo:
```bash
git config core.hooksPath hooks/
```
Before your first push (but only once), you will need to install the [.NET local tools](https://docs.microsoft.com/en-us/dotnet/core/tools/local-tools-how-to-use) which form part of the pre-push hook:
```bash
dotnet tool restore
```
In future, some commits (such as big-bang formatting commits) may be recorded for convenience in `.git-blame-ignore-revs`.
Consider performing the following command to have `git blame` ignore these commits, when we ever create any:
```bash
git config blame.ignoreRevsFile .git-blame-ignore-revs
```
## Dependencies
I try to keep this repository's dependencies as few as possible, because (for example) any consumer of the source generator will also consume this project via the attributes.
When adding dependencies, you will need to `nix run .#fetchDeps` to obtain a new copy of [the dependency lockfile](./nix/deps.nix).
## Branch strategy
Releases are made from the `main` branch.
## License
This project is licensed with the MIT license, a copy of which you can find at the repository root.

View File

@@ -5,217 +5,109 @@ namespace PureGym
open System open System
open System.Text.Json.Serialization open System.Text.Json.Serialization
/// Describes the opening hours of a given gym.
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type GymOpeningHours = type GymOpeningHours =
{ {
/// If this is true, there should be no OpeningHours (but nothing enforces that).
IsAlwaysOpen : bool IsAlwaysOpen : bool
/// This is a pretty unstructured list, which is in general not really parseable: it's human-readable only.
OpeningHours : string list OpeningHours : string list
} }
/// Human-readable representation
override this.ToString () =
if this.IsAlwaysOpen then
"always open"
else
this.OpeningHours |> String.concat ", "
/// How a human can authenticate with a gym when they physically try to enter it
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type GymAccessOptions = type GymAccessOptions =
{ {
/// This gym has PIN entry pads
PinAccess : bool PinAccess : bool
/// This gym has a QR code scanner. QR codes can be generated with the PureGym app.
QrCodeAccess : bool QrCodeAccess : bool
} }
/// Where a gym is on the Earth
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type GymLocation = type GymLocation =
{ {
/// Measured in degrees
[<JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)>] [<JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)>]
Longitude : float Longitude : float
/// Measured in degrees
[<JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)>] [<JsonNumberHandling(JsonNumberHandling.AllowReadingFromString)>]
Latitude : float Latitude : float
} }
/// The postal address of a gym
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type GymAddress = type GymAddress =
{ {
/// E.g. "Canterbury Court"
[<JsonRequired>] [<JsonRequired>]
AddressLine1 : string AddressLine1 : string
/// E.g. "Units 4, 4A, 5 And 5A"
AddressLine2 : string option AddressLine2 : string option
/// E.g. "Kennington Park"
AddressLine3 : string option AddressLine3 : string option
/// E.g. "LONDON"
[<JsonRequired>] [<JsonRequired>]
Town : string Town : string
County : string option County : string option
/// E.g. "SW9 6DE"
[<JsonRequired>] [<JsonRequired>]
Postcode : string Postcode : string
} }
/// Human-readable statement of the address
override this.ToString () =
[
yield Some this.AddressLine1
yield this.AddressLine2
yield this.AddressLine3
match this.County with
| None -> yield Some $"%s{this.Town} %s{this.Postcode}"
| Some county ->
yield Some this.Town
yield Some $"%s{county} %s{this.Postcode}"
]
|> Seq.choose id
|> String.concat "\n"
/// Metadata about a physical gym
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type Gym = type Gym =
{ {
// The following fields are returned but are always null
// ReasonsToJoin : string
// VirtualTourUrl : Uri
// PersonalTrainersUrl : Uri
// WebViewUrl : Uri
// FloorPlanUrl : Uri
// StaffMembers : string
/// The name of this gym, e.g. "London Oval"
[<JsonRequired>] [<JsonRequired>]
Name : string Name : string
/// This gym's ID in the PureGym system, e.g. 19
[<JsonRequired>] [<JsonRequired>]
Id : int Id : int
/// I don't know what this status is. Please tell me if you know!
[<JsonRequired>] [<JsonRequired>]
Status : int Status : int
/// Postal address of this gym
[<JsonRequired>] [<JsonRequired>]
Address : GymAddress Address : GymAddress
/// Phone number of this gym, e.g. "+44 1234 567890"
[<JsonRequired>] [<JsonRequired>]
PhoneNumber : string PhoneNumber : string
/// Contact email address for this gym's staff
[<JsonRequired>] [<JsonRequired>]
EmailAddress : string EmailAddress : string
/// When this gym is open
[<JsonRequired>] [<JsonRequired>]
GymOpeningHours : GymOpeningHours GymOpeningHours : GymOpeningHours
/// How a human can physically authenticate when they physically enter this gym
[<JsonRequired>] [<JsonRequired>]
AccessOptions : GymAccessOptions AccessOptions : GymAccessOptions
/// Where this gym is physically located
[<JsonRequired>] [<JsonRequired>]
Location : GymLocation Location : GymLocation
/// The IANA time zone this gym observes, e.g. "Europe/London"
[<JsonRequired>] [<JsonRequired>]
TimeZone : string TimeZone : string
/// This is a date-time in the format yyyy-MM-ddTHH:mm:ss+01 Europe/London
ReopenDate : string ReopenDate : string
} }
/// Human-readable representation of the most important information about this gym
override this.ToString () =
$"""%s{this.Name} (%i{this.Id})
{this.Address}
%s{this.EmailAddress} %s{this.PhoneNumber}
Opening hours: %s{string<GymOpeningHours> this.GymOpeningHours}
%s{string<GymAccessOptions> this.AccessOptions}
"""
/// A human member of PureGym
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type Member = type Member =
{ {
/// This member's ID. This is a fairly large number.
Id : int Id : int
/// No idea what this is - please tell me if you know!
CompoundMemberId : string CompoundMemberId : string
/// First name, e.g. "Patrick"
FirstName : string FirstName : string
/// Last name, e.g. "Stevens"
LastName : string LastName : string
/// ID of the gym designated as this user's home gym. This is also the "Id" field of the appropriate Gym object.
HomeGymId : int HomeGymId : int
/// The name of the gym designated as this user's home gym. This is also the "Name" field of the appropriate
/// Gym object.
HomeGymName : string HomeGymName : string
/// This user's email address
EmailAddress : string EmailAddress : string
/// This user's gym access pin, probably 8 digits
GymAccessPin : string GymAccessPin : string
/// This user's recorded date of birth
[<JsonPropertyName "dateofBirth">] [<JsonPropertyName "dateofBirth">]
DateOfBirth : DateOnly DateOfBirth : DateOnly
/// This user's phone number, human-readable
MobileNumber : string MobileNumber : string
/// This user's registered home postcode
[<JsonPropertyName "postCode">] [<JsonPropertyName "postCode">]
Postcode : string Postcode : string
/// E.g. "Corporate"
MembershipName : string MembershipName : string
MembershipLevel : int MembershipLevel : int
SuspendedReason : int SuspendedReason : int
MemberStatus : int MemberStatus : int
} }
/// Statistics for how many people are currently at a gym
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type GymAttendance = type GymAttendance =
{ {
/// This appears always to be just equal to TotalPeopleInGym, but a string.
[<JsonRequired>] [<JsonRequired>]
Description : string Description : string
/// How many people are in the gym as of this statistics snapshot
[<JsonRequired>] [<JsonRequired>]
TotalPeopleInGym : int TotalPeopleInGym : int
/// How many people are in classes at the gym as of this statistics snapshot
[<JsonRequired>] [<JsonRequired>]
TotalPeopleInClasses : int TotalPeopleInClasses : int
/// E.g. " or fewer"
TotalPeopleSuffix : string option TotalPeopleSuffix : string option
[<JsonRequired>] [<JsonRequired>]
IsApproximate : bool IsApproximate : bool
/// When the query was received (I think)
AttendanceTime : DateTime AttendanceTime : DateTime
/// When the "total people in gym" snapshot was taken that is reported here
LastRefreshed : DateTime LastRefreshed : DateTime
/// When the "number of people in classes" snapshot was taken that is reported here
LastRefreshedPeopleInClasses : DateTime LastRefreshedPeopleInClasses : DateTime
/// Maximum capacity of the gym, or 0 if no listed capacity
MaximumCapacity : int MaximumCapacity : int
} }
/// The visit statistics for a particular human to a particular gym.
/// The semantics of this class are basically unknown.
type MemberActivityThisMonth =
{
/// How many minutes, including classes, have been logged so far this month
TotalDurationMinutes : int
/// How long, in minutes, each visit has been on average this month
AverageDurationMinutes : int
/// How many visits have been made this month, excluding classes
TotalVisits : int
/// How many classes have been attended this month
TotalClasses : int
/// Whether this block of statistics is estimated rather than exact
IsEstimated : bool
/// When this data was constructed
LastRefreshed : DateTime
}
/// Don't use this type. It's public because System.Text.Json can't do private types.
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type MemberActivityDto = type MemberActivityDto =
{ {
@@ -233,85 +125,41 @@ type MemberActivityDto =
LastRefreshed : DateTime LastRefreshed : DateTime
} }
member this.ToMemberActivity () =
{
TotalDurationMinutes = this.TotalDuration
AverageDurationMinutes = this.AverageDuration
TotalVisits = this.TotalVisits
TotalClasses = this.TotalClasses
IsEstimated = this.IsEstimated
LastRefreshed = this.LastRefreshed
}
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type SessionsAggregate = type SessionsAggregate =
{ {
/// Number of gym "activities" within some query-defined time period; presumably this is like classes?
/// It's always 0 for me.
Activities : int Activities : int
/// Number of visits to the gym within some query-defined time period.
Visits : int Visits : int
/// In minutes: total time spent in gym during the query-defined time period.
Duration : int Duration : int
} }
/// The DTO for gym info returned from the Sessions endpoint.
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type VisitGym = type VisitGym =
{ {
// Omitting Location, GymAccess, ContactInfo, TimeZone because these were all null for me
/// The PureGym ID of this gym, e.g. 19
Id : int Id : int
/// E.g. "London Oval", the canonical name of this gym
Name : string Name : string
/// For some reason this always seems to be "Blocked"
Status : string Status : string
} }
/// Summary of a single visit to a gym.
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type Visit = type Visit =
{ {
// Omitted Name because it always was null for me
/// Whether the Duration field is estimated.
IsDurationEstimated : bool IsDurationEstimated : bool
/// When the visit began.
StartTime : DateTime StartTime : DateTime
/// In minutes.
Duration : int Duration : int
/// Which gym was visited
Gym : VisitGym Gym : VisitGym
} }
/// Human-readable non-round-trip representation.
override this.ToString () =
let startTime = this.StartTime.ToString "yyyy-MM-dd HH:mm"
$"%s{this.Gym.Name}: %s{startTime} (%i{this.Duration} minutes)"
/// Aggregate statistics for gym visits across a time period.
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type SessionsSummary = type SessionsSummary =
{ {
/// Aggregate stats for gym visits within the query-dependent time period.
Total : SessionsAggregate Total : SessionsAggregate
/// Aggregate stats for gym visits "this week", whatever that means to PureGym.
ThisWeek : SessionsAggregate ThisWeek : SessionsAggregate
} }
/// Human-readable non-round-trip representation.
override this.ToString () =
$"%i{this.Total.Visits} visits, totalling %i{this.Total.Duration} minutes"
[<WoofWare.Myriad.Plugins.JsonParse>] [<WoofWare.Myriad.Plugins.JsonParse>]
type Sessions = type Sessions =
{ {
Summary : SessionsSummary Summary : SessionsSummary
Visits : Visit list Visits : Visit list
} }
/// Human-readable non-round-trip representation.
override this.ToString () =
let summary = string<SessionsSummary> this.Summary
let visits = this.Visits |> Seq.map string<Visit> |> String.concat "\n"
$"%s{summary}\n%s{visits}"

View File

@@ -7,10 +7,22 @@
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder> <DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors> <TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarnOn>FS3559</WarnOn> <WarnOn>FS3559</WarnOn>
<DebugType>embedded</DebugType>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.128" PrivateAssets="all" /> <PackageReference Include="Nerdbank.GitVersioning" Version="3.6.128" PrivateAssets="all" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" /> <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
<SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com" /> <SourceLinkGitHubHost Include="github.com" ContentUrl="https://raw.githubusercontent.com" />
</ItemGroup> </ItemGroup>
<!--
SourceLink doesn't support F# deterministic builds out of the box,
so tell SourceLink that our source root is going to be remapped.
-->
<Target Name="MapSourceRoot" BeforeTargets="_GenerateSourceLinkFile" Condition="'$(SourceRootMappedPathsFeatureSupported)' != 'true'">
<ItemGroup>
<SourceRoot Update="@(SourceRoot)">
<MappedPath>Z:\CheckoutRoot\WoofWare.Myriad\</MappedPath>
</SourceRoot>
</ItemGroup>
</Target>
</Project> </Project>

View File

@@ -1,34 +1,13 @@
# fsharp-arguments # WoofWare.Myriad.Plugins
Some helpers in [Myriad](https://github.com/MoiraeSoftware/myriad/) which might be useful for someone writing an argument parser. Some helpers in [Myriad](https://github.com/MoiraeSoftware/myriad/) which might be useful.
## `RemoveOptions` These are currently somewhat experimental, and I personally am their primary customer.
The `RemoveOptions` generator in particular is extremely half-baked.
Takes a record like this: Currently implemented:
* `JsonParse` (to stamp out `jsonParse : JsonNode -> 'T` methods);
```fsharp * `RemoveOptions` (to strip `option` modifiers from a type).
type Foo =
{
A : int option
B : string
C : float list
}
```
and stamps out a record like this:
```fsharp
[<RequireQualifiedAccess>]
module Foo =
type Short =
{
A : int
B : string
C : float list
}
```
(This is a proof of concept. It would be better to somehow disambiguate the module name.)
## `JsonParse` ## `JsonParse`
@@ -86,3 +65,66 @@ module JsonRecordType =
let A = node.["a"].AsValue().GetValue<int>() let A = node.["a"].AsValue().GetValue<int>()
{ A = A; B = B; C = C; D = D } { A = A; B = B; C = C; D = D }
``` ```
### What's the point?
`System.Text.Json`, in a `PublishAot` context, relies on C# source generators.
The default reflection-heavy implementations have the necessary code trimmed away, and result in a runtime exception.
But C# source generators [are entirely unsupported in F#](https://github.com/dotnet/fsharp/issues/14300).
This Myriad generator expects you to use `System.Text.Json` to construct a `JsonNode`, and then the generator takes over to construct a strongly-typed object.
### Limitations
This source generator is enough for what I first wanted to use it for.
However, there is *far* more that could be done.
* Make it possible to give an exact format and cultural info in date and time parsing.
* Make it possible to reject parsing if extra fields are present.
* Rather than just throwing `NullReferenceException`, print out the field name that failed.
* Generally support all the `System.Text.Json` attributes.
## `RemoveOptions`
Takes a record like this:
```fsharp
type Foo =
{
A : int option
B : string
C : float list
}
```
and stamps out a record like this:
```fsharp
[<RequireQualifiedAccess>]
module Foo =
type Short =
{
A : int
B : string
C : float list
}
```
### What's the point?
The motivating example is argument parsing.
An argument parser naturally wants to express "the user did not supply this, so I will provide a default".
But it's not a very ergonomic experience for the programmer to deal with all these options,
so this Myriad generator stamps out a type *without* any options, and also stamps out an appropriate constructor function.
### Limitations
This generator is *far* from where I want it, because I haven't really spent any time on it.
* It really wants to be able to recurse into the types within the record, to strip options from them.
* It needs some sort of attribute to mark a field as *not* receiving this treatment.
* What do we do about discriminated unions?
# Detailed examples
See the tests.
For example, [PureGymDto.fs](./ConsumePlugin/PureGymDto.fs) is a real-world set of DTOs.

View File

@@ -7,6 +7,7 @@
<Copyright>Copyright (c) Patrick Stevens 2023</Copyright> <Copyright>Copyright (c) Patrick Stevens 2023</Copyright>
<Description>Provides some Myriad compile-time code generation plugins.</Description> <Description>Provides some Myriad compile-time code generation plugins.</Description>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<RepositoryUrl>https://github.com/Smaug123/WoofWare.Myriad</RepositoryUrl>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageReadmeFile>README.md</PackageReadmeFile> <PackageReadmeFile>README.md</PackageReadmeFile>
<PackageTags>myriad;fsharp;source-generator;source-gen;json</PackageTags> <PackageTags>myriad;fsharp;source-generator;source-gen;json</PackageTags>
@@ -27,6 +28,10 @@
<Compile Include="JsonParseGenerator.fs" /> <Compile Include="JsonParseGenerator.fs" />
<None Include="version.json" /> <None Include="version.json" />
<EmbeddedResource Include="SurfaceBaseline.txt" /> <EmbeddedResource Include="SurfaceBaseline.txt" />
<None Include="..\README.md">
<Pack>True</Pack>
<PackagePath>\</PackagePath>
</None>
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.Build.NoTargets/1.0.80"> <!-- This is not a project we want to build. -->
<PropertyGroup>
<IsPackable>false</IsPackable>
<IsPublishable>false</IsPublishable>
<RestorePackagesPath>../.analyzerpackages/</RestorePackagesPath>
<TargetFramework>net6.0</TargetFramework>
<DisableImplicitNuGetFallbackFolder>true</DisableImplicitNuGetFallbackFolder>
<AutomaticallyUseReferenceAssemblyPackages>false</AutomaticallyUseReferenceAssemblyPackages> <!-- We don't want to build this project, so we do not need the reference assemblies for the framework we chose.-->
</PropertyGroup>
<ItemGroup>
<PackageDownload Include="G-Research.FSharp.Analyzers" Version="[0.6.0]" />
</ItemGroup>
</Project>

View File

@@ -14,11 +14,11 @@
}: }:
flake-utils.lib.eachDefaultSystem (system: let flake-utils.lib.eachDefaultSystem (system: let
pkgs = nixpkgs.legacyPackages.${system}; pkgs = nixpkgs.legacyPackages.${system};
pname = "fsharp-arguments"; pname = "WoofWare.Myriad.Plugins";
dotnet-sdk = pkgs.dotnet-sdk_8; dotnet-sdk = pkgs.dotnet-sdk_8;
dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0; dotnet-runtime = pkgs.dotnetCorePackages.runtime_8_0;
version = "0.1"; version = "0.1";
dotnetTool = toolName: toolVersion: sha256: dotnetTool = dllOverride: toolName: toolVersion: sha256:
pkgs.stdenvNoCC.mkDerivation rec { pkgs.stdenvNoCC.mkDerivation rec {
name = toolName; name = toolName;
version = toolVersion; version = toolVersion;
@@ -29,17 +29,23 @@
sha256 = sha256; sha256 = sha256;
installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin''; installPhase = ''mkdir -p $out/bin && cp -r tools/net6.0/any/* $out/bin'';
}; };
installPhase = '' installPhase = let
dll =
if isNull dllOverride
then name
else dllOverride;
in ''
runHook preInstall runHook preInstall
mkdir -p "$out/lib" mkdir -p "$out/lib"
cp -r ./bin/* "$out/lib" cp -r ./bin/* "$out/lib"
makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${name}.dll" makeWrapper "${dotnet-runtime}/bin/dotnet" "$out/bin/${name}" --add-flags "$out/lib/${dll}.dll"
runHook postInstall runHook postInstall
''; '';
}; };
in { in {
packages = { packages = {
fantomas = dotnetTool "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version "sha256-Jmo7s8JMdQ8SxvNvPnryfE7n24mIgKi5cbgNwcQw3yU="; fantomas = dotnetTool null "fantomas" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fantomas.version "sha256-Jmo7s8JMdQ8SxvNvPnryfE7n24mIgKi5cbgNwcQw3yU=";
fsharp-analyzers = dotnetTool "FSharp.Analyzers.Cli" "fsharp-analyzers" (builtins.fromJSON (builtins.readFile ./.config/dotnet-tools.json)).tools.fsharp-analyzers.version "sha256-wDS7aE4VI718iwU8xUm0aCOYIcFpMuqWu9+H5d+8XAA=";
fetchDeps = let fetchDeps = let
flags = []; flags = [];
runtimeIds = ["win-x64"] ++ map (system: pkgs.dotnetCorePackages.systemToDotnetRid system) dotnet-sdk.meta.platforms; runtimeIds = ["win-x64"] ++ map (system: pkgs.dotnetCorePackages.systemToDotnetRid system) dotnet-sdk.meta.platforms;
@@ -60,7 +66,7 @@
})); }));
default = pkgs.buildDotnetModule { default = pkgs.buildDotnetModule {
pname = pname; pname = pname;
name = "argument-helpers"; name = "WoofWare.Myriad.Plugins";
version = version; version = version;
src = ./.; src = ./.;
projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj"; projectFile = "./WoofWare.Myriad.Plugins/WoofWare.Myriad.Plugins.fsproj";

View File

@@ -1,6 +1,11 @@
# This file was automatically generated by passthru.fetch-deps. # This file was automatically generated by passthru.fetch-deps.
# Please don't edit it manually, your changes might get overwritten! # Please don't edit it manually, your changes might get overwritten!
{fetchNuGet}: [ {fetchNuGet}: [
(fetchNuGet {
pname = "fsharp-analyzers";
version = "0.22.0";
sha256 = "sha256-wDS7aE4VI718iwU8xUm0aCOYIcFpMuqWu9+H5d+8XAA=";
})
(fetchNuGet { (fetchNuGet {
pname = "fantomas"; pname = "fantomas";
version = "6.3.0-alpha-005"; version = "6.3.0-alpha-005";