Showing posts with label don't talk to me about life. Show all posts
Showing posts with label don't talk to me about life. Show all posts

Wednesday, November 16, 2022

Hacking Fake.Build for net7.0

It's too early yet to do the AltCover after-action for net7.0 like I did for net5.0; but it is proving a slog like net5.0 rather than being too transparent to mention like net6.0 was.

While the dotnet 7.0.100 build has its own problems, the Fake build system currently (5.23.x, 6.0 alpha) doesn't handle it at all - the former may work for limited scenarios, but more complicated ones fall over with library version mismatches; the latter politely askes for a v6 runtime and stops.

So, you have a build process based on a Fake script, but want to run with v7.0.100 as SDK, through your project global.json. What do?

Well, the Fake documentation gives some alternatives - turn the script into a net7.0 project that links against the Fake libraries; but that imposes some restrictions on how you set up targets, because you can only define such things (as opposed to the functions that define the target's intended action) after setting up a build context. Or you can run as a fsi script, but the documentation then leads into how to hack paket into the mix.

However, since net5.0, scripts are able to reference nuget packages directly, so rather than having a paket.dependencies, with a #r "paket: groupref [whatever] //", and a call out to paket on the command line, your scripts can be self-contained, with a block of #r "nuget: [library][, optional version]" lines at the top, and a command line that is just dotnet fsi [my fake script.fsx]

And doing it this way, you can build on the net7.0 runtime.

Wednesday, October 13, 2021

F# and OpenSilver v1.0

An update to the previous series of posts following the first stable release of OpenSilver.

While the details of which lines of code in the Browser and Simulator projects need to be redirected at the F# types have changed since the earlier posts at alpha-7 release, the principle remains the same -- where the generated code refers to the C#/XAML App type, replace that with the derived F# type. The F# (logic) and C# (just the XAML, reified as abstract base types) are set up exactly as before.

If you're porting an old solution, from a pre-release OpenSilver, unless you've been staying on the bleeding edge, it's simpler to start by creating a new one, copying the F# project and the XAML project from old to overwrite the new, and otherwise starting from scratch, remembering to check in all the as-generated files before making the edits.

At this point, provided that all the repointing to the F# project and types is done correctly, it should all "just work".

There is one gotcha, though, that has appeared in the updates for publishing the Browser WASM since my alpha-7 exploration, in that some potentially very long file paths can now be invoked that point deep under the project's default obj subfolder. If your project is already down a few layers from the drive root it will run foul of the Copy MSBuild task which appears to still labour under the old DOS MAX_PATH of 255 characters. Copying to an overlong path fails by timing out, so breaking the build. In that case add

    <IntermediateOutputPath>shorter file path here</IntermediateOutputPath>
    <BaseIntermediateOutputPath>$(IntermediateOutputPath)</BaseIntermediateOutputPath>

where a suitable up-tree location is specified e.g. starting at the top of the repo, or in a shallow build output directory outside the repo, rather than as a child of a project directory. Note that both values need to be set and aligned, lest defaults be assumed during the process.

The resulting code can be found here.

Wednesday, November 18, 2020

AltCover -- the road to .net 5, F# 5, and GitHub actions

A for the record listing of what was needed to make the transition for a project that's over a decade old -- the current GitHub repo is only 3 years old, but that was formed by grafting the relevant contents of the original 2010-vintage SVN history onto a 2H17 git bootstrap.

In the original 10Q2-11Q1 development, the build system was a PowerShell script that called msbuild on the .net3.5 solution, then did an automated copy and edit to also build against .net4; taking up the reins again in 17Q3, the latter were used as the basis for going forwards. Over time, parallel .net core projects were added, which eventually subsumed the originals.

Thus, on the eve of the .net5 release, we had

  • A main solution targeting net472 (debug only) and netstandard2.0 for libraries; net472, netcoreapp2.0 and netcoreapp2.1 for tooling with netcoreapp3.0 for unit tests
  • A separate solution building a net20 library (the run-anywhere recorder) plus tests at net20/net472/netcoreapp3.0
  • A separate solution for the GUI tool, targeting net472 (debug only) and netstandard2.0 for libraries, net472 with a reference to the GTK2# assemblies in the GAC, and netcoreapp2.1 for tooling and netcoreapp3.0 for unit tests
  • Finally a solution for building a front end to the Mono C# compiler library, used to provide test data, still in the old project style

So, all very good and mostly modern -- the transition should have been trivial then...

Not so fast...

Once I had the F#5 compiler installed, that broke the net20 build (looking for a System.Numerics.dll which was still part of FSharp.Core in net20). Applying an earlier F# compiler via NuGet package fixed that in Visual Studio, but then dotnet build failed, so I had to resort to msbuild-ing the recorder solution. But then on the travis-ci build, that meant that the net5.0 (upgraded from netcoreapp3.0) unit test target got interpreted as .net Framework 5.0, and the build failed for lack of approprate referenced assemblies. So, as you were before with the unit tests, at least for the moment.

At this point, one obvious result of maintaining backwards compatibility by building deliverable executables (and unit tests) against older netcoreapp* targets, but with "rollForwardOnNoCandidateFx": 2 in runtimeconfig.template.json was a profusion of NETSDK1138 obsolescence warnings; silenced by building with /p:CheckEolTargetFramework="false" all around.

Where I'd been running ahead of AppVeyor's current installed .net SDKs, I'd been using Chocolatey to bring down the version I wanted; time to be aware that the package has been renamed from dotnetcore-sdk to dotnet-sdk instead.

That got things building on the "traditional" CI servers, so, a good time to make a first try of GitHub Actions for CI as well.

With the at-time-of-writing latest windows and linux platforms, that meant that I didn't have a "modern enough" msbuild.exe on the PATH for the recorder and the GUI tool. To resolve that, I resorted to finding the path of the MSBuild.dll from the current .net5 SDK (via parsing the output of dotnet --info for the Base Path: value), and lashing up a way to use it with Fake's MSBuild command line construction support.

Fall-out from this was needing to compile string resources ahead of time for the recorder -- no ResGen.exe support in the new regime -- and use the same (earlier) compiler for all the test platforms; also creating a set of reference assemblies for GTK#2, so I could avoid having any reference to the GAC (meaning that the GUI tool solution would now dotnet build, even if I still have to MSBuild the recorder solution). The Mono C# compiler project -- also using MSBuild -- which still made references out to .targets files out in Visual Studio or Windows SDK parts of MSBuildExtensionsPath32-land also needed attention; as a retro project, I simply added the earlier F# compiler package here, too, to make it build.

On the plus side, now the net20 project is using the MSBuild executable from the net5 SDK, switching the unit tests all round to target net5.0 works as one would hope it to work.

Wednesday, June 24, 2020

Snagging just the Windows Spotlight Lock-screen images

One of the annoying things about Windows Spotlight is that at times, it includes advertising junk in the screen text. Somewhat more annoying is when a picture comes up, you wonder what it's a picture of, but the screen text never shows.

There are plenty of articles out there which tell you how to capture all the OS image assets and leave you to manually sort through them. Noting that the lock screen images will be of recent date, it's actually much easier to automate the entire process in a few lines of PowerShell --

which pulls just the phone and desktop images into the current directory for you; this means you can then use the standard means of identifying images to attempt to answer questions like "Spain or old California?", "England or New England?"

Tuesday, March 17, 2020

March Cycling (COVID-19 edition)

On the winter bike starting at 16767.4 and ending at 16831.5 when the advice to stay at home and shelter in place came out, for a total of 64.1 miles (231.2 YTD). Bang! go all the long spring rides, and the 30 days of cycling in April, that I'd been planning.

Later (27th) -- a spell of fine weather near the end of the month encouraged me out for a short burst of fresh air after doing end-of-winter maintenance on the bike, to spot where the terrible road leading out of the village had been completely resurfaced in the past couple of weeks. Total numbers become 16835.7, 68.3 and 235.4 respectively.

Monday, August 05, 2019

F# under the covers XVII -- Code reuse loopiness

For some level of complexity and size, the F# compiler is happy to say "I've already done something like that, let's jump back and do it again!" putting an apparent loop into iteration-free code. It's not a common thing -- I've seen it exactly once the the FSharp.Core v4.7 library --

        match t1, t2 with
        | SetEmpty, t2  -> add comparer k t2 // drop t1 = empty 
        | t1, SetEmpty  -> add comparer k t1 // drop t2 = empty 
        | SetOne k1, t2 -> add comparer k (add comparer k1 t2)
        | t1, SetOne k2 -> add comparer k (add comparer k2 t1)
        | SetNode (k1, t11, t12, h1), SetNode (k2, t21, t22, h2) ->

The IL for this contains the expected forward conditional jumps from the match to the cases, but the second SetOne case preps the k2, t1 arguments then jumps backwards into the middle of the previous case, and exits after completing the shared call structure.

 IL_0029: ldloc.2
 IL_002a: isinst class Microsoft.FSharp.Collections.SetTree`1/SetOne
 IL_002f: brtrue.s IL_0055

 // item2 = t2;
 IL_0031: ldarg.3
 IL_0032: stloc.0
 // item = setOne.item;
 IL_0033: ldloc.1
 IL_0034: ldfld !0 class Microsoft.FSharp.Collections.SetTree`1/SetOne::item
 IL_0039: stloc.3

 // return add(comparer, k, add(comparer, item, item2));
 IL_003a: ldarg.0
 IL_003b: ldarg.2
 IL_003c: ldarg.0
 IL_003d: ldloc.3
 IL_003e: ldloc.0
 IL_003f: call class Microsoft.FSharp.Collections.SetTree`1 Microsoft.FSharp.Collections.SetTreeModule::'add'(class [mscorlib]System.Collections.Generic.IComparer`1, !!0, class Microsoft.FSharp.Collections.SetTree`1)
 IL_0044: call class Microsoft.FSharp.Collections.SetTree`1 Microsoft.FSharp.Collections.SetTreeModule::'add'(class [mscorlib]System.Collections.Generic.IComparer`1, !!0, class Microsoft.FSharp.Collections.SetTree`1)
 // (no C# code)
 IL_0049: ret

 // item2 = t1;
 IL_004a: ldarg.1
 IL_004b: stloc.0

 // return add(comparer, k, item2);
 IL_004c: ldarg.0
 IL_004d: ldarg.2
 IL_004e: ldloc.0
 IL_004f: call class Microsoft.FSharp.Collections.SetTree`1 Microsoft.FSharp.Collections.SetTreeModule::'add'(class [mscorlib]System.Collections.Generic.IComparer`1, !!0, class Microsoft.FSharp.Collections.SetTree`1)
 // (no C# code)
 IL_0054: ret

 // item2 = t2;
 IL_0055: ldarg.3
 // item = setOne.item;
 IL_0056: ldloc.1
 IL_0057: ldfld !0 class Microsoft.FSharp.Collections.SetTree`1/SetOne::item
 IL_005c: stloc.3
 // (no C# code)
 IL_005d: stloc.0
 IL_005e: br.s IL_003a

This provided an interesting exercise for the branch-chasing algorithm in AltCover (inspired by the one in OpenCover), which hadn't anticipated a backwards leap inside a sequence point, and went off into a spin until told to look for ret and similar termination points.

Friday, April 05, 2019

End of an era

Sometime near the start of 1995, I finally got with the program, and got myself a 14k4 modem and a Demon Internet account.

Years passed, ADSL arrived, Demon became Thus became Vodafone. Then a few weeks back, notification that their ADSL offering was being retired, but there was no equipment in our local exchange to simply translate to fibre-to-cabinet. So I've had to uproot all the SOHO-style home network with its static IP to another ISP and dynamic IP.

It's taken a couple of days, but it all (internal servers, externally-facing servers, DNS, general net access) seems to be working now.

And 20 years on, the fibre that Cambridge Cable laid to the village in 1999 has never been built upon either, so we don't even have fibre-to-premise as an option.

Update, 7-Apr: Outbound mail from my domain names is still not working.

Update, 7-Apr, later: Outbound mail, this time via my domain registrar, might be working now.

Update 14-Apr: Finally after 10 days, I think I may now have the mails from my cron jobs being handled properly by Google (SPF passing and getting to the correct folder).


Thursday, January 10, 2019

A Blogger infelicty I just hit

Entering the string %00 in the editor like this .Replace('\', ), gives a nul in the page which isn't returned to a %-escape when editing the entry, so I had to use &#37;00 instead to achieve .Replace('\', %00).


Yet another MSBuild-on-Linux back-slash gotcha

Another variant of a known family of such issues, encountered as AltCover issue #49, the interesting tale of what you get when your MSBuild sets a task array parameter with

AssemblyExcludeFilter="$(AltCoverAssemblyExcludeFilter.Split('|'))"

and the value of AltCoverAssemblyExcludeFilter is the-|xunit\.; surprisingly, the answer is

the-
xunit/.

There isn't even an explicit ItemList in sight, and yet the '\' still gets interpreted as a path separator and "helpfully" *nix-ified. Doubling up the '\' via .Replace('\','\\') ahead of the split doesn't escape the character -- you just get a '//' in the output, nor does escaping on the command line as the-|xunit%5C..

For the moment, with no obvious MSBuild level fix, I'm working around this by doing .Replace('\', %00) and then converting the NUL back inside the custom MSBuild task.


Thursday, January 03, 2019

Moving on from G+

With the G+ sunset brought forwards to April, time to move my microblogging -- which is what I actually used G+ for, rather than the community aspects -- to proper microblogging sites, plural for redundancy.

So you can now find me on the Twitter (@stevegilham1) and Gab (@stevegilham), and maybe more later.

Tuesday, November 20, 2018

RIP rawgit

Going to put a new package on NuGet, the icon doesn't come out. So I paste the rawgit URL into the browser directly to check what's up and get a 403 that directs to https://rawgit.com/, which says the service is being sun-setted, offering the following possible alternatives.

For me, the first one "just works"™, so that's what I'm migrating to, at least for the moment.


Wednesday, May 09, 2018

Assembly versioning is hard -- internals just keep on leaking

I've hit a couple of instances of this in recent weeks.

Assembly versioning is meant to be a strong contract, that given two distinct instances with the same version, one can be used as a drop-in replacement for the other, e.g. as a a bug-fixing patch, in all circumstances. A sufficiently strong contract, indeed, that in my experience in building commercial product with .net, our process erred on the side of caution, and bumped the build number facet of the version every commit, even if all that had changed were dependencies.

However, it doesn't always work that way.

The first instance I hit was when Mono.Cecil finally hit 0.10 final after having been in beta for years. That had indeed preserved its public contract -- but somewhere between beta-7 and final, one of the internal APIs consumed by the symbol-reading helper assemblies via InternalsVisibleTo was expanded. Consequently, if a beta version was loaded (e.g. by a tool -- in particular the NUnit3 test adapter for .net core) ahead of the final, the result was a MissingMethodException when indirectly invoking that internal path. I specify .net core here, because the lack of AppDomain isolation is what puts the tool's use of beta-6 into the pot ahead of the system under test's final.

The most recent has been with Visual Studio 2017, which also bundles an update to the F# core assembly version 4.4.3.0, and the FSharpLint MSBuild task. Here, the F# compiler's choice of generating synthetic names for compiler generated classes by tagging them with @lineNumber comes into its own -- the new file version "2018.04.25.1" includes an internal synthetic type related to event handling called Microsoft.FSharp.Control.CommonExtensions+SubscribeToObservable@1693; in the earlier "2018.01.25.1" build, the corresponding type is Microsoft.FSharp.Control.CommonExtensions+SubscribeToObservable@1741 and asking for the former when the latter is the one on offer gets you a TypeLoadException. Here, it looks like AppDomain isolation is working against us in the other direction, with different and thus incompatible builds of FSharp.Code.dll being loaded in two separate AppDomains.


Sunday, February 05, 2017

SHA256.Create() and "Works on my machine" FIPS-compliance

I've just had an interesting run-in with a little-advertised and not backwards-compatible feature in .net 4.6 and up, and how it affects FIPS-compliance, for those of us who have to worry about such things.

You see, in the recent .net versions (unlike the older ones), the selection of the default implementation toggles on whether the machine has HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Lsa\FipsAlgorithmPolicy\[Enabled] set non-zero or not (or the equivalent group policy), and will select a FIPS-certified implementation for SHA256 (and SHA384 and SHA512), and, interestingly only for those flavours of SHA-2, using exactly the same criterion as is used to make the non-compliant implementations raise an exception on construction. So, assuming no app or machine level overrides, the matrix looks like this:

SHA###.Create()
no FIPS enforcementFIPS enforced
.net 4.6 and up

(Dev machine)
SHA###Managed

OK
SHA###Cng

"Works on my machine."
.net 4.5.2 or earlier

(Slow-moving customer environment)
SHA###Managed

OK
SHA###Managed

KABOOM!

The end-stop selection of algorithm defaults (where not overridden by a specific [class].Create()) in .net 4.5.2 are drawn from mscorlib alone, many FIPS-compliant, with the notable exceptions being the "new" (SHA-2, or AES which is present only by the original name of Rijndael), or old-and-deprecated (like MD5) algorithms. As in most cases, [DerivedClass].Create() is just a synonym for [BaseAlgorithm].Create(), you can get a false sense of security here -- SHA256CryptoServiceProvider.Create() will equally spit out an instance of SHA256Managed in three of the cases above, and SHA256Cng in the fourth ("works on my machine").

TL;DR -- if you have to worry about FIPS, don't use [Algorithm].Create(), but select the one you mean by calling its constructor explicitly.


Sunday, January 22, 2017

Yet another thread 'main' panicked Rust gotcha -- mind your build.rs

Picking up the little Rust project I'd set aside in late summer, with the latest release, I got

thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Error { repr: Os { code: 2, message: "The system
 cannot find the file specified." } }', ../src/libcore\result.rs:837

Setting environment variable RUST_BACKTRACE to 1, and retrying gave

stack backtrace:
   0:   0xf314b7 - std::panicking::default_hook
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libstd\panicking.rs:263
   1:   0xf31caa - std::panicking::rust_panic_with_hook
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libstd\panicking.rs:451
   2:   0xf31b47 - std::panicking::begin_panic<collections::string::String>
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libstd\panicking.rs:413
   3:   0xf31a86 - std::panicking::begin_panic_fmt
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libstd\panicking.rs:397
   4:   0xf319e2 - std::panicking::rust_begin_panic
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libstd\panicking.rs:373
   5:   0xf36f82 - core::panicking::panic_fmt
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libcore\panicking.rs:69
   6:   0xf22402 - core::result::unwrap_failed<std::io::error::Error>
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libcore\macros.rs:29
   7:   0xf21d0f - core::result::Result<std::process::ExitStatus, std::io::error::Error>::unwrap<std::process::ExitStatu
s,std::io::error::Error>
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libcore\result.rs:737
   8:   0xf23b5e - build_script_build::main
                at c:\Users\steve\hg\Projects\rust\HelloWorld\build.rs:8
   9:   0xf3556b - panic_unwind::__rust_maybe_catch_panic
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libpanic_unwind\lib.rs:97
  10:   0xf322f0 - std::rt::lang_start
                at C:\bot\slave\stable-dist-rustc-win-msvc-32\build\src\libstd\rt.rs:51
  11:   0xf23d01 - main
  12:   0xf39768 - __scrt_common_main_seh
                at f:\dd\vctools\crt\vcstartup\src\startup\exe_common.inl:253
  13: 0x75168e93 - BaseThreadInitThunk
  14: 0x772d9bc2 - RtlDestroyQueryDebugBuffer

which wasn't particularly helpful.

Resolution was an inspired guess -- my build.rs contained a path which ran a command by explicit path into the windows SDK for an x64 machine, when I was trying on an old 32-bit box.

Fixing the path to be selected according to whether the file actually exists resolved the issue.



Thursday, January 19, 2017

…and good riddance!

I took this screen-shot in mid-October 2007, well before the primary season that propelled the junior Senator from Illinois onto the national stage--


Today, I have a use for it, at last!

Saturday, December 31, 2016

That was the year that was

This time last year, work, including some extra responsibilities, voluntarily taken on, that had spiralled beyond what I had expected, combined with the commute to the Science Park, and having to keep things functioning on the domestic front, had really ground me down. I didn't even manage to summon up the time and energy for several of the needful gardening chores (woodwork maintenance and apple tree pruning) across the holiday break.

So, sooner than I had planned (meaning to do it this coming year, as a down-shift towards retirement), I applied for reduced working hours, which cut in from the start of May.

That did the trick for the moment -- I've been able to attend more to things that are neither work nor the bare minimum of domestic chores. That included enough time in the garden to do pre-emptive weeding, even suppressing the bindweed as it emerged, as well as time to do more in the kitchen than simply heat up ready-meals every day, while still leaving time to just kick back and unwind. I even managed to do a tiny bit of side-project coding (hence the few posts on Rust in recent months), which is up on the zero I managed in 2015.

In the wider world, what a year it's been, too.

A year ago, we didn't know the date when Cameron (who he?) would call the referendum he'd been bounced into, and I expected it would be late 2017 and the status quo would prevail; and I was expecting that Hillary would comfortably beat whichever of Ted Cruz or Marco Rubio (who they?) won the Republican nomination. At the end of the year, what had transpired was beyond anything I could reasonably have hoped for.

What I hadn't expected was the number of people I follow on the internet who I thought were reasonable and level-headed, yet who completely lost it following the election of a New York liberal to the Presidency, like they actually believed all the "literally Hitler" caricatures.

It all means 2017 is going to be interesting, though I devoutly hope, not too much in the Chinese sense.

Sunday, November 27, 2016

Fixing SMB access in recent Windows 10 updates

One of the updates that came down the wire to the machine I'm running on the insider slow ring in the last few weeks had the effect that trying to access the SMB share on my router gave a message like

\\Remote-Server\Path is not accessible. You might not have permission to use this network resource. Contact the administrator of this server to find out if you have access permissions. etc.

Breaking out Wireshark and comparing a machine still on build 1607 (local account login) with the test machine (MSFT login) showed that the SMB handshake would perform the initial exchange of Session Setup AndX Request, NTLMSSP_NEGOTIATE and Session Setup AndX Response, NTLMSSP_CHALLENGE, Error: STATUS_MORE_PROCESSING_REQUIRED, but the test machine would not then emit a Session Setup AndX Request, NTLMSSP_AUTH, User: Machine\User packet. Further experiment would be needed to tell whether this is because I'm running that machine with a MSFT login rather than a local account, rather than it being an insider build, but in the end, the fix turned out to be going to Control Panel\User Accounts\Credential Manager and creating a new Windows credential just for the Remote-Server address, with username and password sufficient to log on to the share (so for a wide-open read-only share, any username and an empty password will do).

Wednesday, May 18, 2016

Log literacy -- a sadly neglected skill

People who come to this blog for the technical posts may have noticed that those rather dried up over the last couple of years. There was a highly boring reason for this -- having built a little guerilla build server with one of my colleagues, it suddenly took over the world, despite our best intentions. This meant an unexpected amount of DevOps work keeping it running, and continuing to develop what had been first intended to be just a system for our team into one that covered multiple sites in different geos.

Fortunately, success was eventually rewarded by another team writing a competing system, to which my response was "Thank you, very much!" and I have at last been able to shed that particular monkey from my back. In time, that period will become a source of many war stories, but there is one particular thing that I did notice.

The key "new thing" in this system was to chain together the individual component builds that were the elements provided to the formal build process, so we could get to system-testable outputs more quickly, in a manner that could work equally on the build server and the developer's local machine. This, of course, meant that developers would at times see their builds fail in components which they were not familiar with, and then come to the two of us juggling the server (and who might be equally unfamiliar with the failing component) for a resolution.

Some of the time it turned out to be some corner case we hadn't considered in our orchestration process, but often enough it was something environmental that precipitated an otherwise normal failure in the MSBuild based process. It's just that a normal failure ends up with yards of error messages, redoubled by being screaming red text when it's in a console window on your desktop. Something like:

D:\Source\Feature\path\to\component\Library4
\Library4.csproj(##, #): error XXX####: Something went wrong
Done Building Project "D:\Source\Feature\path\to\component\Library4
\Library4.csproj" (default targets) -- FAILED.
Done Building Project "D:\Source\Feature\path\to\component\Library3
\Library3.csproj" (default targets) -- FAILED.
Done Building Project "D:\Source\Feature\path\to\component\Library2a
\Library2a.csproj" (default targets) -- FAILED.
Done Building Project "D:\Source\Feature\path\to\component\Library2
\Library2.csproj" (default targets) -- FAILED.
Done Building Project "D:\Source\Feature\path\to\component\Library1
\Library1.csproj.metaproj" (default targets) -- FAILED.
Done Building Project "D:\Source\Feature\path\to\component\Component
.sln" (default targets) -- FAILED.
Done Building Project "D:\Source\Feature\path\to\component\Build\Buil
dAll.proj" (FullBuild target(s)) -- FAILED.

Build FAILED.

[105 lines of other errors omitted]

"D:\Source\Feature\path\to\component\Build\BuildAll.proj" (FullB
uild target) (1) ->
"D:\Source\Feature\path\to\component\Component.sln
" (default target) (2) ->
"D:\Source\Feature\path\to\component\Library1\Library1.
csproj.metaproj" (default target) (15) ->
"D:\Source\Feature\path\to\component\L
ibrary2\Library2.csproj" (default target) (16) ->
"D:\Source\Feature\path\to\component\L
ibrary.2a\Library2a.csproj" (default target) (18) ->
"D:\Source\Feature\path\to\component\Library3
\Library3.csproj" (default target) (20) ->
"D:\Source\Feature\path\to\component\Library4
\Library4" (default target) (19:2) ->
  D:\Source\Feature\path\to\component\Library4
\Library4.csproj(##, #): error XXX####: Something went wrong

    0 Warning(s)
    7 Error(s)

This, it turns out, is enough to make even many quite senior developers throw their hands up in horror, when it happens in an unfamiliar piece of code -- even though, a few hundred lines earlier, there will usually be an obvious root cause, maybe something quite blatant, like:

PreBuildEvent:
  PowerShell.exe -File "D:\Source\Feature\Path\to
\component\Scripts\Do-Something.ps1" [arguments]
  The argument 'D:\Source\Feature\Path\to\component\Scripts\Do-
Something.ps1' to the -File parameter does not exist. Provide the path to an existing '.ps1' file as an argument
to the -File parameter.

which simply wasn't emitted as an error or warning in the MSBuild meaning of the terms, and so wasn't highlighted, or re-iterated, but which would be the start of what would become a cascade of FAILED and Error red text.

This phenomenon of a failure log ending with things going horribly wrong, but with a seemingly innocuous line much earlier that indicates when things started to go bad is not just restricted to MSBuild logs, or even build logs in general.

And that is the nice case. There can be worse. Sometimes the error messages at the end may be entirely unrelated to what actually failed or at best be only tangentially related (e.g. tidying operations failing when what they are supposed to tidy didn't get created) -- so trying to reason from them can be a hiding to nothing.


So when confronted by a failure log that seems to conclude with notification that the sky is falling for no good reason, take a deep breath, refuse to panic, and just start at the top. You might not always be able to resolve the issue personally, but you'll most likely be able to provide a better problem report to the person who can.

Thursday, March 10, 2016

The Great Detune

In the early days of this century, Planet Rock was notable for two things -- reception where we live was atrocious, and they played Psycho-Killer about every third track. But as the years passed, the digital coverage improved, as did the variety of the playlists.

So at the end of last month Planet Rock were announcing that they were moving to a different channel, but all you had to do was press a couple of buttons on your radio to retune.

So far so good -- getting the full list of channels, and moving from zPlntRck to PlntRock was easy.

Actually getting a signal has been another matter. Where I used to have a radio alarm on my bedside, now I can only get a signal by putting the thing on the middle of the bedroom windowsill, and the radio plugged into the hi-fi downstairs is on the ragged edge of sufficient signal to noise at best.

At least we don't get Psycho-Killer on repeat this time around.

Monday, February 29, 2016

February Cycling

Up to 13,613.7, 2689.7 and 16.1, meaning 347.2 + 0 + 10 = 357.2 miles (686.2 YTD, 60% up on last year) in colder, drier and not so windy weather; without any excursions on the long route this time.

I did have one puncture, where a spoke rubbed through the rim-tape, and it took a while to get the -- new in December -- back wheel aligned again (realizing that both the washers that had been put on on one side were needed inside the frame to position the wheel properly between the brake pads, as a hack because the adjustment screw on one side doesn't engage properly). And then when I got the chain done, I had to move one of the washers back into place inside the frame again after I got home, having been warned that one pad was rubbing slightly...

For the moment the hack is working, but in due course, I guess it's time for a new set of calipers.