Monday, 24 August 2020

Mocking AspNet Core IHttpClientFactory for tests using Moq

Having not written any dotnet code for several years, I recently needed to write a basic web server that would receive a request, and as part of its work, it would send a request to another web server.

Being a fan of TDD, I wanted to do it in a test-driven way, which meant having to figure out how to mock the response from the other server. Searching the internet, it seems that the way to make web requests is to use an IHttpClientFactory to create an HttpClient. My first thought was that I would need to mock the client, but notice that HttpClient is a concrete class, and so can't be mocked using a mocking library such as Moq. Searching for what was the right approach here, I came across this blog post, which got me most of the way there:

using Xunit;
using Microsoft.AspNetCore.Mvc;
using Moq;
using System.Net.Http;
using System.Threading.Tasks;
using Moq.Protected;
using System.Threading;
using System.Net;
using MyNamespace.Controllers;

namespace MyNamespace.Tests.Controllers
{
public class MyControllerTest
{

[Fact]
public async Task MyTest()
{
var clientFactory = new Mock<IHttpClientFactory>();
var messageHandler = new Mock<HttpMessageHandler>();
messageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.NoContent
})
.Verifiable();
var client = new HttpClient(messageHandler.Object);
clientFactory.Setup(_ => _.CreateClient()).Returns(client);
MyController controller =
new MyController(clientFactory.Object);

var result = await controller.ProcessRequest() as StatusCodeResult;

Assert.Equal((int)HttpStatusCode.NoContent, result.StatusCode);
}
}
}

However, the test then failed with the following error:

  Error Message:
   System.NotSupportedException : Unsupported expression: _ => _.CreateClient()
Extension methods (here: HttpClientFactoryExtensions.CreateClient) may not be used in setup / verification expressions.

After some head-scratching, I finally realised that the CreateClient() method is actually an extension method so you need to mock the underlying method that that calls, which is CreatClient(string). Making this simple change resulted in a passing test!

Here is the updated test, with that single line changed.

        [Fact]
public async Task MyTest()
{
var clientFactory = new Mock<IHttpClientFactory>();
var messageHandler = new Mock<HttpMessageHandler>();
messageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.NoContent
})
.Verifiable();
var client = new HttpClient(messageHandler.Object);
clientFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
MyController controller =
new MyController(clientFactory.Object);

var result = await controller.ProcessRequest() as StatusCodeResult;

Assert.Equal((int)HttpStatusCode.NoContent, result.StatusCode);
}

For completeness, here is the code for the controller method that is being tested:

namespace MyNamespace.Controllers
{
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

public class MyController : Controller
{
private IHttpClientFactory clientFactory;

public MyController(IHttpClientFactory clientFactory)
{
this.clientFactory = clientFactory;
}

public IActionResult Index()
{
return Ok();
}

public async Task<IActionResult> ProcessRequest()
{
var request = new HttpRequestMessage(
HttpMethod.Get,
"http://localhost/some/path");
request.Headers.Add("Accept", "application/json");

var client = clientFactory.CreateClient();

var response = await client.SendAsync(request);

if (response.IsSuccessStatusCode)
{
return NoContent();
}
else
{
return StatusCode(500);
}
}
}
}


Thursday, 1 December 2016

Configuring DNS for an OpenVPN server behind a Virgin Media Hub 3.0

I recently had my old Virgin Media SuperHub replaced with a Hub 3.0. After this, I found that my VPN clients were no longer working. The first thing I needed to do was enable port-forwarding for port 1194 using the Hub 3.0's admin web interface. This was fairly easy to achieve (once I figured out that, for some reason, the admin interface really doesn't like it if you are using a browser in private/incognito mode).

With port-forwarding re-enabled, my VPN clients could connect to the server, but any attempts to access websites would encounter a DNS-resolution failure. To diagnose the issue, I connected to the PI using ssh and then tried using curl to access a website.


    ssh pi@<ip-address-of-pi>
    
    curl https://www.google.co.uk/

This worked fine, proving that DNS lookup worked fine from the PI. After a bit of internet searching, I came across this entry on the OpenVPN forums: https://forums.openvpn.net/viewtopic.php?t=21678. Realising that this explained how the OpenVPN server informs the client what DNS server to use, I had a look at the configuration for my OpenVPN server.


    sudo vi /etc/openvpn/server.conf

Inside this file was the line that had been added when originally setting up the server:


    push "dhcp-option DNS 192.168.0.1"

This is the IP address of the router, so I wondered if this new router was doing DNS differently.

I also realised that my computer was not encountering any DNS issues, so I took a look at its network settings. Sure enough, the DNS server was set to a different address: 194.168.4.100. This address is also the address that was listed under "IPv4 DNS servers" on the Info section of the Admin tab on the router's interface. I therefore updated the line in the server.conf file to use that address.


    push "dhcp-option DNS 194.168.4.100"

With this done, I restarted the OpenVPN server.


    sudo service openvpn restart

Once it was restarted I tried connecting my client again, and voilĂ ! I could now surf the internet again using my VPN connection.

Sunday, 19 July 2015

Using a Raspberry PI as a VPN Server

Having toyed with the idea for a while of setting up a VPN server at home, I was finally inspired to actually do something about it when I watched Kate Russel on BBC Click talk about how she'd set up such a system using a Raspberry PI. Deciding to strike while the iron was hot, I took advantage of my Amazon Prime membership and ordered a Raspberry PI for next day delivery.

Arriving before 0930 Sunday morning, I immediately unpacked it and set about following the instructions in the article. What follows is a few things that tripped me up a bit / weren't immediately obvious to me, split out into sections with the same names as the ones in the article.

Install Raspbian on your Rasberry Pi

A minor detail, but since the instructions don't include attaching a mouse, it isn't necessarily obvious how to "choose Raspbian and click install". To do so, use the arrow keys to highlight the Raspbian option, press the Enter key to select it and then press the i key to begin installation.

Once installed, upon booting up for the first time, a configuration screen is shown. I used this to enable SSH so that I would be able to administer the box without needing to leave a keyboard connected.

Give your Raspberry Pi a static IP address

It's not necessary to run the ifconfig command with sudo. However, the reboot command at the end does require it.

There's a slight mismatch between the names of the values referenced in the article and how they're actually displayed in the output of the ifconfig command:

Name in article Name in ifconfig output
Current IP Address inet addr
Broadcast Range Bcast
Subnet Mask Mask

The line that the article states is "iface eth0 inet dhcp" was actually "iface eth0 inet manual" in my file.

When running "sudo nano etc/network/interfaces" there is a missing leading slash; the command should be "sudo nano /etc/network/interfaces". When editing the file, although I'm not sure if it's actually necessary, the address, netmask, network, broadcast and gateway lines are usually indented under the "iface eth0 inet static" line (at least in most of the examples I found on the web).

Set up an easy control system

I used a Mac to connect to the PI over SSH, so I didn't need to install a separate SSH client. I did, however, need to connect as the pi user (by default, ssh will try and connect using the username of the current user on the Mac). This was done by entering the command:

ssh pi@[ip-address-of-my-pi]
from the command prompt on my Mac.

Update your Raspberry Pi

A very minor thing that might confuse inexperienced users, is that when running the "sudo apt-get upgrade" command, it will display how much extra space will be taken up (in my case it was actually less space!) and ask if you wish to continue. To continue, simply press the y key followed by the Enter key.

Similarly, when running the "sudo apt-get install openvpn" command, press the y key followed by the Enter key when asked if you wish to continue.

Build keys for each user

After choosing to sign the certificate, it asks "1 out of 1 certificate requests certified, commit? [y/n]", press the y key followed by the Enter key.

After running "openssl rsa -in KateAndroid.key -des3 -out KateAndroid.3des.key", the pass-phrase for the .key file is the one previously entered when running the build-key-pass command (so ignore the note about making it one you can remember), the next one is a new one for the .3des.key file.

Generate the Diffie-Hellman key exchange.

Just as a warning, when running the build-dh command, I kicked it off from an ssh session on my Mac. I then went away to do other stuff whilst waiting for the command to complete. When I came back an hour or so later, however, it appeared to not have completed, nor be progressing. I hit the Enter key and received the following message:


Write failed: Broken pipe
I decided to start it again, but this time directly on the PI (by connecting a keyboard and monitor to it). It actually completed pretty quickly the second time, so I guess the progress it had made from the first run got saved; thankfully I didn't have to wait another hour or so.

Ensure you have a static public IP address

I tried to sign up for an account with DNS Dynamic, as per the article; however, despite trying a couple of different email addresses, I never received a confirmation email and was unable to log in with the credentials I used on the sign-up page. I ended up going with an alternative dynamic DNS provider - ChangeIP.

When I ran the "sudo apt-get install ddclient" command, it launched a wizard for configuring ddclient. Unfortunately, it was unclear what options to choose in the wizard and I could find nothing on the ChangeIP website to help me. Fortunately, someone had already figured out how to configure OpenVPN to work with ChangeIP, so after choosing some options using the wizard (that turned out to be mostly correct), I edited my /etc/ddclient.conf file as per this blog post.

The ddclient command should be run with sudo: sudo ddclient

Create profile scripts for the devices you want to connect

When editing the files in this section, nano should be preceded with sudo, e.g. "nano /etc/openvpn/easy-rsa/keys/Default.txt" should be "sudo nano /etc/openvpn/easy-rsa/keys/Default.txt".

For the creation of the Default.txt file, [YOUR PUBLIC IP ADDRESS] should be replaced with your dynamic DNS value (e.g. [your-chosen-subdomain].dynamic-dns.net), not an IP address.

When creating the MakeOVPN.sh file, there are two lines that should actually be a single line:


#Ready to make a new .opvn file - Start by populating with the
default file
(The above two lines should be a single line.)

Export your client keys for use on the connecting devices

I would not recommend running the command "chmod 777 -R /etc/openvpn" followed by "chmod 600 -R /etc/openvpn". Once complete, this will end up with all files and directories under /etc/openvpn having read and write permission only by the file/directory owner. This means that all the scripts will no longer be executable. In my case, I was able to use the scp command to copy the .ovpn file, after having granted permission to read the file itself and all parent directories.


# Run from a command prompt on the Raspberry PI
chmod 777 /etc/openvpn
chmod 777 /etc/openvpn/easy-rsa
chmod 777 /etc/openvpn/easy-rsa/keys
chmod 777 /etc/openvpn/easy-rsa/keys/[ClientName].ovpn

# Run from the computer you wish to download the file to
scp pi@[ip-address-of-your-pi]:/etc/openvpn/easy-rsa/keys/[ClientName].ovpn [ClientName].ovpn

Install the OpenVPN Connect app on your device

When importing the key, the PEM pass-phrase that is needed is the one used when creating the 3des.key file.

One more thing

After all this was done, my phone still couldn't connect to the OpenVPN server. I then realised that although I'd followed the instructions to open up the firewall on the PI itself, I hadn't done anything about the firewall on my router. Once I updated my router to do port-forwarding of port 1194 to the PI, everything worked swimmingly!

Sunday, 21 June 2015

Problems With The Sunfounder Starter Kit For Arduino

Recently, work had some Sunfounder Arduino kits delivered to the office for people to experiment with. I thought I'd borrow one of the Starter Learning Kits and work my way through the lessons.

Recently opened starter-kit

As I encountered some problems getting started, I thought I'd document these here, both for my own reference and in case it's of use to anybody else.

Problem: Contents

According to the contents list, there's supposed to be 18 LEDs, comprised of 8 x Red, 5 x Yellow and 5 x Blue. The way they've been bagged up is in a group of 5, 3 and 10. There seems to be no way to determine what colour each is (they just look clear when not turned on) and as I haven't tried plugging them all in, I don't yet know whether they are in fact the right number of each colour or not.

There are also apparently supposed to be 30 male to female jumper wires, but there are actually only 10.

The contents lists 10 buttons, and there are actually 10 buttons…plus another 4 smaller ones that get no mention at all (though are used in the first lesson).

Problem: DVD Size

Rather than ship a full-size DVD with the kit, a mini-DVD is included. The problem with that is that these don't work in slot-loading drives. Luckily for me, I have a PC with a disc-tray type drive on it, so I was able to use that machine to copy the contents of the DVD off and then network share that with other machines.

Problem: Photo/Diagram Size

The booklet with all the lessons in is pretty small:

Small lesson booklet

(Coin included for scale.) The text even more so. Whilst my eyesight is good enough to read the general copy (well, once I've put my glasses on, anyway), I struggle to read the text on some of the diagrams, making them quite hard to interpret.

Problem: Photos Don't Match pictures

Each lesson includes a schematic, a diagram and a photo. The problem is that the photo and the diagram often don't match exactly. Now, I realise that there are an almost infinite number of ways to wire-up the components into the same actual electrical circuit, but as a beginner, it would really help if the photo and diagram exactly replicated each other. I don't really have a grasp yet of how everything connects up and having this discrepancy makes it difficult to spot where I've gone wrong when things don't work.

Another aspect of the photos that don't quite tie up with the instructions is that, in the photo for lessons 1 and 2, the Arduino board is being powered via the DC input, and not via the USB connection. This is a smaller issue than some of the others, but can still be a bit off-putting when trying to follow something to the letter and there is a mis-match between what the text says to do (use the USB cable) and what the photo demonstrates.

Problem: No Explanation Of Breadboards

The lessons do include a "Principle" section providing some background to the current lesson, but one thing it doesn't do at any point is detail how the breadboard works. This caused me some problems as when something didn't work, I didn't have a clear enough understanding of what the underlying electrical circuit was as I didn't know how the holes on the breadboard were actually connected together inside. I ended up searching the internet and came across a good explanation here. I was quite proud of myself, once I'd read this to then be able to fix the problem I was having with lesson 3, Interactive LED Flowing Lights.

Problem: Booklet Lessons Don't Match Website

When I was encountering problems following the lessons in the booklet, I tried visiting the Sunfounder website. Unfortunately, the particular lesson I was having difficulties with (lesson 3, Interactive LED Flowing Lights) does not seem to actually exist there. It has a flowing lights lesson and it has a potentiometer lesson but not one that has the two together as exists in the booklet.

Problem: The Code

The lessons in the booklet are all about the hardware—wiring the components together. The only reference to code in each lesson is when you get to the second step:

Step 2: Program (Please refer to the example code in our CD)

It then goes on to the next step:

Step 3: Compile and debug the program
Step 4: Burn the program into SUNFOUNDER UNO board

This is far from the level of instructions necessary to achieve anything. If you look at the contents of the DVD, it contains a directory for each lesson and one more for "fritzing". At no point is it explained what Fritzing is or what it is for (it turns out that within each lesson directory is a circuit sub-directory that contains a .FZZ file that Fritzing can be used to open—it then displays the diagram that is shown in the booklet).

Also in the lesson directory is a code sub-directory that contains a single .INO file. Nowhere is it stated what the format of this file is (it's actually just a text file) or what application can be used to open it. After some more searching of the Internets, I discovered that .INO files are used to store Arduino sketches. These sketches can be compiled and uploaded to Arduino boards using the Arduino Development Environment. Instructions on how to get started can be found here, which links to getting started instructions for Windows, Linux and Mac.

Problem: Resistors

According to the contents, there are 5 x 10K resistors, 5 x 1K resistors and 8 220R resistors. The resistors are packaged in 3 groups of sizes 8, 5 and 5; thus it seems reasonable to assume that the group of 8 is the 220R resistors, but what about the two groups of five? There's no indication in the booklet about how to differentiate them. There are some coloured bands around them and the labels that the resistors are stuck to have a coloured band on, but nowhere does it state what any of these mean (I still have no idea what the coloured bands on the labels indicate).

Resistor side-by-side comparison

There are various websites that explain how the colour-coding system on resistors works. My main problem though is telling which way round to read them. Since these resistors are 5-band and contain one on the bulge at each end and 3 in the mid-section it doesn't seem possible (to me at least) to work out which way round they should be read.

Inputting the band colours into the calculator here results in a rating of 10K for the green-labelled resistors if read with the green label on the left or 120 if read the other way around. Similarly, for the red-labelled resistors the values are 110 and 1K respectively. This would seem to indicate that the green-labelled resistors are 10K ones and the red-labelled ones are 1K ones. It is slightly worrying though that they have to be read opposite way rounds to each other in order to reach these numbers (i.e. the green-labelled ones should be read with the label on the left and the red-labelled ones should be read with the label on the right). Once removed from the labels it also becomes even harder to know which are which.

Conclusion

That just about sums up the problems I've encountered trying to complete the first 3 lessons in the booklet. Hopefully this will save someone else time in the future so they don't get as frustrated as I did. Enjoy, and good luck!

Here is a photo of my solution to the "Interactive LED Flowing Lights" lesson, complete with working speed control!

Sunday, 21 April 2013

Amending A Previous (But Not The Most Recent) Git Commit

Sometimes I have a few local git commits that are yet to be pushed. Occasionally when this happens, I realise that one of those commits is broken (e.g. I forgot to include something in it). In such cases the following is a useful means of editing a previous commit.

WARNING: Attempting to do this for a commit that has been shared with others (e.g. by pushing to Github) may cause serious injury or death (ok, probably not, but it might cause a bit of upset).

If you have the changes to apply in your work area, stash them now.

Identify the commit before the one to be amended (you'll need its commit hash). Use a tool such as GitX (L) if you like (or you can just use git-log).

Run git-rebase: git rebase -i <commit-hash>

This will bring up an edit window (in vim on my machine). Each commit after the one identified by <commit-hash> will be listed and will be initially prefixed by pick. For the commit you want to amend, change pick to edit. Save and exit (i.e. :wq in vim).

Make the required amendments to the commit (e.g. git stash apply if those changes had been stashed).

git add -p to stage those changes.

git commit --amend to amend the commit.

git rebase --continue to apply any subsequent commits.

Et voila, your commit history has been updated!

Simples.

Sunday, 25 September 2011

Autoresizing Masks in the Cocoa Framework

I've been struggling a bit to get my head around exactly how the different UIViewAutoresizing values work together. This post is an examination of trying out various combinations and documenting the effects.

The first thing to do is set up two views, one within the other. Then, the autoresizingMask of the inner view is set and the frame of the outer view changed.

This is what the two views look like before any resizing:


Below are the results of changing the size of the outer view's frame, using various values for the inner view's autoresizingMask property.

UIViewAutoresizingNone:
This causes the inner view's frame to remain unchanged.


UIViewAutoresizingFlexibleTopMargin:
This causes only the y coordinate of the inner view's frame to change.


UIViewAutoresizingFlexibleBottomMargin:
This causes the inner view's frame to remain unchanged.


UIViewAutoresizingFlexibleLeftMargin:
This causes only the x coordinate of the inner view's frame to change.


UIViewAutoresizingFlexibleRightMargin:
This causes the inner view's frame to remain unchanged.


UIViewAutoresizingFlexibleWidth:
This causes only the width of the inner view's frame to change.


UIViewAutoresizingFlexibleHeight:
This causes only the height of the inner view's frame to change.


UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleHeight:
This causes the y coordinate and height of the inner view's frame to change.


UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleWidth:
This causes the x coordinate and width of the inner view's frame to change.

Saturday, 17 September 2011

MacPorts & Mono

Problem updating MacPorts and have Mono installed? Read on...

I was setting up my Mac Book Pro so that I could work on the RapidFTR project and I ran into some trouble. The instructions for installing and running RapidFTR on OSX specify that MacPorts should be installed. Having downloaded the installer for version 2.0.1, I ran the sudo port selfupdate command as suggested; here began my trouble:


---> Updating MacPorts base sources using rsync
MacPorts base version 2.0.1 installed,
MacPorts base version 2.0.3 downloaded.
---> MacPorts base is outdated, installing new version 2.0.3
Installing new MacPorts release in /opt/local as root:admin; permissions 0755; Tcl-Package in /Library/Tcl

Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: shell command failed (see log for details)


This wasn't particularly helpful, though there was a vague statement about some log file (nothing so helpful as where this file might be located though!). Having no idea where to look for the log, I looked in /var/log. This contained a bunch of log files, though none of them looked specific to MacPorts. OK, I thought, perhaps it puts them in system.log.

Turns out it doesn't.

My next idea was to look in install.log, as an update is a kind of installation, right?

Turns out it doesn't put it in here either.

However, what I DID see in here was the output from running the original 2.0.1 installer package. It turns out that this had also tried to perform an update and it too had failed (not that it reported this when I ran it, mind). Amongst its output there was a suggestion of running the selfupdate command with the -d flag to get more specific output. Running this command produced the following output (only the key part is included):


In file included from entryobj.c:36:
/Library/Frameworks/Mono.framework/Versions/2.10.3/include/sqlite3.h:252: warning: ISO C90 does not support ‘long long’
/Library/Frameworks/Mono.framework/Versions/2.10.3/include/sqlite3.h:253: warning: ISO C90 does not support ‘long long’
/usr/bin/cc -dynamiclib -g -O2 -W -Wall -pedantic -I/Library/Frameworks/Mono.framework/Versions/2.10.3/include -Wl,-single_module registry.o util.o entry.o entryobj.o ../cregistry/cregistry.a -o registry.dylib -L/System/Library/Frameworks/Tcl.framework/Versions/8.5 -ltclstub8.5 -L/Library/Frameworks/Mono.framework/Versions/2.10.3/lib -lsqlite3
ld: warning: ignoring file /Library/Frameworks/Mono.framework/Versions/2.10.3/lib/libsqlite3.dylib, file was built for unsupported file format which is not the architecture being linked (x86_64)
Undefined symbols for architecture x86_64:
"_sqlite3_errmsg", referenced from:
_set_sqlite_result in util.o
_reg_sqlite_error in cregistry.a(registry.o)
_reg_detach in cregistry.a(registry.o)
_reg_close in cregistry.a(registry.o)
_reg_attach in cregistry.a(registry.o)
_reg_open in cregistry.a(registry.o)
"_sqlite3_mprintf", referenced from:
_set_object in util.o
_set_entry in util.o
_get_object in util.o
_reg_sqlite_error in cregistry.a(registry.o)
_reg_detach in cregistry.a(registry.o)
_reg_attach in cregistry.a(registry.o)
_reg_open in cregistry.a(registry.o)
...

<!--Bunch of other _sqlite* symbols-->
...
"_sqlite3_changes", referenced from:
_reg_entry_delete in cregistry.a(entry.o)
_reg_entry_deactivate in cregistry.a(entry.o)
_reg_entry_activate in cregistry.a(entry.o)
_reg_entry_unmap in cregistry.a(entry.o)
"_sqlite3_column_text", referenced from:
_reg_entry_files in cregistry.a(entry.o)
_reg_entry_imagefiles in cregistry.a(entry.o)
_reg_entry_propget in cregistry.a(entry.o)
"_sqlite3_value_text", referenced from:
_sql_regexp in cregistry.a(sql.o)
"_sqlite3_result_int", referenced from:
_sql_regexp in cregistry.a(sql.o)
"_sqlite3_result_error", referenced from:
_sql_regexp in cregistry.a(sql.o)
"_sqlite3_create_function", referenced from:
_init_db in cregistry.a(sql.o)
"_sqlite3_create_collation", referenced from:
_init_db in cregistry.a(sql.o)
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make[2]: *** [registry.dylib] Error 1
make[1]: *** [all] Error 1
make: *** [all] Error 1
shell command "cd /opt/local/var/macports/sources/rsync.macports.org/release/tarballs/base && CC=/usr/bin/cc ./configure --prefix=/opt/local --with-tclpackage=/Library/Tcl --with-install-user=root --with-install-group=admin --with-directory-mode=0755 --enable-readline && make && make install" returned error 2
DEBUG: Error installing new MacPorts base: shell command failed (see log for details)
while executing
"macports::selfupdate [array get global_options] base_updated"
Error: /opt/local/bin/port: port selfupdate failed: Error installing new MacPorts base: shell command failed (see log for details)


This seemed to suggest that it might be something to do with the Mono installation I had…With this extra information in hand, I was finally able to perform a search that turned up a useful result (in fact it was the only result). Buried within this set of email threads was the key message:


> It appears the problem is MacPorts is grabbig SQLite from
>
> /Library/Frameworks/Mono.framework/Versions/2.10.3/include/sqlite3.h
>
> Obviously, part of the problem is that the version of SQlite being
> found/used is from the Mono SDK (installed from go-mono.com),
> installed at /Library/Frameworks/Mono.framework.

You nailed it: that's precisely the issue.

>
> The odd thing: As far as I can tell, MacPorts should be using the
> frameworks in /opt/local/Library/Frameworks:
> (from the configure script output:)
> checking for Frameworks installation directory...
> /opt/local/Library/Frameworks
>
> What do I need to do to get 'port selfupdate' to ignore the Mono framework
> in
> /Library/Frameworks
> And use the one(s) in
> /opt/local/Library/Frameworks?

In this instance, when MacPorts is checking that directory it is for
creating it and not using it. MacPorts will use the SQLite from:
/usr/include/sqlite3.h
or applicable Xcode SDKs.

As a workaround, I'd recommend you move the mono framework temporarily out
of /Library/Frameworks, selfupdate MacPorts, and then put your Mono
framework back.


So I tried doing this (sudo mv /Library/Frameworks/Mono.framework/ ), et voilĂ , retrying the MacPort selfupdate worked!