Skip to content

Commit 7dbc8aa

Browse files
mhutchmathewc
authored andcommitted
Enable building and running on Mono/Mac
1 parent 160d54a commit 7dbc8aa

File tree

16 files changed

+344
-210
lines changed

16 files changed

+344
-210
lines changed

src/WebJobs.Script.WebHost/App_Start/WebHostResolver.cs

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -153,14 +153,10 @@ private static ScriptHostConfiguration CreateScriptHostConfiguration(WebHostSett
153153
// If running on Azure Web App, derive the host ID from the default subdomain
154154
// Otherwise, derive it from machine name and folder name
155155
string hostId = _settingsManager.AzureWebsiteDefaultSubdomain;
156+
156157
if (string.IsNullOrEmpty(hostId))
157158
{
158-
var sanitizedPath = Path.GetFileName(Environment.CurrentDirectory)
159-
.Where(char.IsLetterOrDigit)
160-
.Aggregate(new StringBuilder(), (b, c) => b.Append(c))
161-
.ToString();
162-
163-
hostId = $"{Environment.MachineName}-{sanitizedPath}";
159+
hostId = MakeValidHostId($"{Environment.MachineName}-{Path.GetFileName(Environment.CurrentDirectory)}");
164160
}
165161

166162
if (!String.IsNullOrEmpty(hostId))
@@ -181,6 +177,51 @@ private static ScriptHostConfiguration CreateScriptHostConfiguration(WebHostSett
181177
return scriptHostConfig;
182178
}
183179

180+
private static string MakeValidHostId(string id)
181+
{
182+
var sb = new StringBuilder();
183+
184+
//filter for valid characters
185+
foreach (var c in id)
186+
{
187+
if (c == '-')
188+
{
189+
//dashes are valid
190+
//but it cannot start with one
191+
//nor can it have consecutive dashes
192+
if (sb.Length != 0 && sb[sb.Length - 1] != '-')
193+
{
194+
sb.Append(c);
195+
}
196+
}
197+
else if (char.IsDigit(c))
198+
{
199+
//digits are valid
200+
sb.Append(c);
201+
}
202+
else if (char.IsLetter(c))
203+
{
204+
//letters are valid but must be lowercase
205+
sb.Append(char.ToLowerInvariant(c));
206+
}
207+
}
208+
209+
//it cannot end with a dash
210+
if (sb.Length > 0 && sb[sb.Length - 1] == '-')
211+
{
212+
sb.Length -= 1;
213+
}
214+
215+
//length cannot exceed 32
216+
const int MaximumHostIdLength = 32;
217+
if (sb.Length > MaximumHostIdLength)
218+
{
219+
sb.Length = MaximumHostIdLength;
220+
}
221+
222+
return sb.ToString();
223+
}
224+
184225
private static void InitializeFileSystem(string scriptPath)
185226
{
186227
if (ScriptSettingsManager.Instance.IsAzureEnvironment)

src/WebJobs.Script.WebHost/Global.asax.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ protected void Application_Start()
2222
protected void Application_Error(object sender, EventArgs e)
2323
{
2424
// TODO: Log any unhandled exceptions
25-
Exception ex = Server.GetLastError();
2625
}
2726

2827
protected void Application_End(object sender, EventArgs e)

src/WebJobs.Script.WebHost/Properties/Resources.resx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,7 @@
183183
</data>
184184
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
185185
<data name="Homepage" type="System.Resources.ResXFileRef, System.Windows.Forms">
186-
<value>..\Home.html;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
186+
<value>../Home.html;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089;utf-8</value>
187187
</data>
188188
<data name="HostSecretsSchemaV0" xml:space="preserve">
189189
<value>{

src/WebJobs.Script.WebHost/WebJobs.Script.WebHost.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,9 @@
4646
<ErrorReport>prompt</ErrorReport>
4747
<WarningLevel>4</WarningLevel>
4848
</PropertyGroup>
49+
<PropertyGroup Condition="'$(OS)'=='Unix'">
50+
<DefineConstants>$(DefineConstants);MONO</DefineConstants>
51+
</PropertyGroup>
4952
<ItemGroup>
5053
<Reference Include="Autofac, Version=4.2.1.0, Culture=neutral, PublicKeyToken=17863af14b0044da, processorArchitecture=MSIL">
5154
<HintPath>..\..\packages\Autofac.4.2.1\lib\net45\Autofac.dll</HintPath>

src/WebJobs.Script.WebHost/WebScriptHostExceptionHandler.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,9 @@ public async Task OnTimeoutExceptionAsync(ExceptionDispatchInfo exceptionInfo, T
4848

4949
// We can't wait on this as it may cause a deadlock if the timeout was fired
5050
// by a Listener that cannot stop until it has completed.
51-
Task ignoreTask = _manager.StopAsync();
51+
#pragma warning disable 4014
52+
_manager.StopAsync();
53+
#pragma warning restore 4014
5254

5355
// Give the manager and all running tasks some time to shut down gracefully.
5456
await Task.Delay(timeoutGracePeriod);
@@ -69,4 +71,4 @@ private void LogErrorAndFlush(string message, Exception exception)
6971
_manager.Instance.TraceWriter.Flush();
7072
}
7173
}
72-
}
74+
}

src/WebJobs.Script.WebHost/WebScriptHostManager.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,12 @@ public void Initialize()
142142
{
143143
if (!_webHostSettings.IsSelfHost)
144144
{
145+
// FIXME: Mono does not yet support HostingEnvironment.QueueBackgroundWorkItem
146+
#if MONO
147+
Task.Run(() => WarmUp(_webHostSettings));
148+
#else
145149
HostingEnvironment.QueueBackgroundWorkItem((ct) => WarmUp(_webHostSettings));
150+
#endif
146151
}
147152
else
148153
{
@@ -156,7 +161,12 @@ public void Initialize()
156161
{
157162
if (!_webHostSettings.IsSelfHost)
158163
{
164+
// FIXME: This behaves a little differently on Mono as it does not handle cancellation
165+
#if MONO
166+
Task.Run(() => RunAndBlock());
167+
#else
159168
HostingEnvironment.QueueBackgroundWorkItem((ct) => RunAndBlock(ct));
169+
#endif
160170
}
161171
else
162172
{

src/WebJobs.Script/Description/DotNet/CSharp/CSharpCompilation.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,14 @@ public Assembly EmitAndLoad(CancellationToken cancellationToken)
9696
{
9797
var compilationWithAnalyzers = _compilation.WithAnalyzers(GetAnalyzers());
9898
var diagnostics = compilationWithAnalyzers.GetAnalyzerDiagnosticsAsync().Result;
99-
var emitResult = compilationWithAnalyzers.Compilation.Emit(assemblyStream, pdbStream, cancellationToken: cancellationToken);
99+
var emitOptions = new EmitOptions().WithDebugInformationFormat(
100+
#if WINDOWS
101+
DebugInformationFormat.Pdb
102+
#else
103+
DebugInformationFormat.PortablePdb
104+
#endif
105+
);
106+
var emitResult = compilationWithAnalyzers.Compilation.Emit(assemblyStream, pdbStream, options: emitOptions, cancellationToken: cancellationToken);
100107

101108
diagnostics = diagnostics.AddRange(emitResult.Diagnostics);
102109

src/WebJobs.Script/Description/DotNet/FSharp/FSharpCompilationService.cs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,13 +83,13 @@ public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata)
8383

8484
var assemblyName = FunctionAssemblyLoader.GetAssemblyNameFromMetadata(functionMetadata, Guid.NewGuid().ToString());
8585
var assemblyFileName = Path.Combine(scriptPath, assemblyName + ".dll");
86-
var pdbName = Path.ChangeExtension(assemblyFileName, "pdb");
86+
var pdbName = Path.ChangeExtension(assemblyFileName, PlatformHelper.IsMono ? "dll.mdb" : "pdb");
8787

8888
try
8989
{
9090
var scriptFileBuilder = new StringBuilder();
9191

92-
// Write an adjusted version of the script file, prefixing some 'open' decarations
92+
// Write an adjusted version of the script file, prefixing some 'open' declarations
9393
foreach (string import in script.Options.Imports)
9494
{
9595
scriptFileBuilder.AppendLine("open " + import);
@@ -129,6 +129,13 @@ public ICompilation GetFunctionCompilation(FunctionMetadata functionMetadata)
129129
otherFlags.Add("--tailcalls-");
130130
}
131131

132+
if (PlatformHelper.IsMono)
133+
{
134+
var monoDir = Path.GetDirectoryName(typeof(string).Assembly.Location);
135+
var facadesDir = Path.Combine(monoDir, "Facades");
136+
otherFlags.Add("--lib:" + facadesDir);
137+
}
138+
132139
// If we have a private assembly folder, make sure the compiler uses it to resolve dependencies
133140
string privateAssembliesFolder = Path.Combine(Path.GetDirectoryName(functionMetadata.ScriptFile), DotNetConstants.PrivateAssembliesFolderName);
134141
if (Directory.Exists(privateAssembliesFolder))

src/WebJobs.Script/Host/ScriptHost.cs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,9 @@ protected ScriptHost(ScriptHostConfiguration scriptConfig)
5454
{
5555
ScriptConfig = scriptConfig;
5656
FunctionErrors = new Dictionary<string, Collection<string>>(StringComparer.OrdinalIgnoreCase);
57+
#if FEATURE_NODE
5758
NodeFunctionInvoker.UnhandledException += OnUnhandledException;
59+
#endif
5860
TraceWriter = ScriptConfig.TraceWriter;
5961
}
6062

@@ -397,14 +399,16 @@ private void RestartHost()
397399
// signal host restart
398400
_restartEvent.Set();
399401

402+
#if FEATURE_NODE
400403
// whenever we're restarting the host, we want to let the Node
401404
// invoker know so it can clear the require cache, etc.
402405
NodeFunctionInvoker.OnHostRestart();
406+
#endif
403407
}
404408

405-
/// <summary>
406-
/// Whenever the debug marker file changes we update our debug timeout
407-
/// </summary>
409+
/// <summary>
410+
/// Whenever the debug marker file changes we update our debug timeout
411+
/// </summary>
408412
private void OnDebugModeFileChanged(object sender, FileSystemEventArgs e)
409413
{
410414
LastDebugNotify = DateTime.UtcNow;
@@ -819,9 +823,13 @@ private Collection<FunctionDescriptor> GetFunctionDescriptors()
819823
var descriptorProviders = new List<FunctionDescriptorProvider>()
820824
{
821825
new ScriptFunctionDescriptorProvider(this, ScriptConfig),
826+
#if FEATURE_NODE
822827
new NodeFunctionDescriptorProvider(this, ScriptConfig),
828+
#endif
823829
new DotNetFunctionDescriptorProvider(this, ScriptConfig),
830+
#if FEATURE_POWERSHELL
824831
new PowerShellFunctionDescriptorProvider(this, ScriptConfig)
832+
#endif
825833
};
826834

827835
return GetFunctionDescriptors(functions, descriptorProviders);
@@ -1174,7 +1182,9 @@ protected override void Dispose(bool disposing)
11741182
_restartEvent.Dispose();
11751183
(TraceWriter as IDisposable)?.Dispose();
11761184

1185+
#if FEATURE_NODE
11771186
NodeFunctionInvoker.UnhandledException -= OnUnhandledException;
1187+
#endif
11781188
}
11791189
}
11801190
}

src/WebJobs.Script/Host/ScriptHostManager.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,9 @@ public bool CanInvoke()
147147
// Orphan the current host instance. We're stopping it, so it won't listen for any new functions
148148
// it will finish any currently executing functions and then clean itself up.
149149
// Spin around and create a new host instance.
150-
Task taskIgnore = Orphan(newInstance);
150+
#pragma warning disable 4014
151+
Orphan(newInstance);
152+
#pragma warning restore 4014
151153
}
152154
catch (Exception ex)
153155
{

0 commit comments

Comments
 (0)