mirror of
https://github.com/aljazceru/btcpayserver-docker.git
synced 2025-12-17 10:44:21 +01:00
Add requires, exclusive and recommended fragments interpreted by the builder
This commit is contained in:
@@ -4,3 +4,6 @@ services:
|
|||||||
btcpayserver:
|
btcpayserver:
|
||||||
ports:
|
ports:
|
||||||
- "80:49392"
|
- "80:49392"
|
||||||
|
|
||||||
|
exclusive:
|
||||||
|
- proxy
|
||||||
@@ -26,4 +26,11 @@ services:
|
|||||||
- "$<BTCPAY_HOST_SSHAUTHORIZEDKEYS>?:${BTCPAY_SSHAUTHORIZEDKEYS}"
|
- "$<BTCPAY_HOST_SSHAUTHORIZEDKEYS>?:${BTCPAY_SSHAUTHORIZEDKEYS}"
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
btcpay_datadir:
|
btcpay_datadir:
|
||||||
|
|
||||||
|
required:
|
||||||
|
- "postgres"
|
||||||
|
- "nbxplorer"
|
||||||
|
- "btcpayserver"
|
||||||
|
recommended:
|
||||||
|
- "opt-add-tor"
|
||||||
@@ -34,4 +34,11 @@ volumes:
|
|||||||
nginx_conf:
|
nginx_conf:
|
||||||
nginx_vhost:
|
nginx_vhost:
|
||||||
nginx_html:
|
nginx_html:
|
||||||
nginx_certs:
|
nginx_certs:
|
||||||
|
|
||||||
|
exclusive:
|
||||||
|
- proxy
|
||||||
|
required:
|
||||||
|
- "btcpayserver-nginx"
|
||||||
|
recommended:
|
||||||
|
- "nginx-https"
|
||||||
@@ -30,3 +30,5 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
BITCOIN_EXTRA_ARGS: |
|
BITCOIN_EXTRA_ARGS: |
|
||||||
dbcache=1024
|
dbcache=1024
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
@@ -37,3 +37,5 @@ services:
|
|||||||
BITCOIN_EXTRA_ARGS: |
|
BITCOIN_EXTRA_ARGS: |
|
||||||
dbcache=50
|
dbcache=50
|
||||||
maxmempool=50
|
maxmempool=50
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
|
|||||||
@@ -30,3 +30,5 @@ services:
|
|||||||
monacoind:
|
monacoind:
|
||||||
environment:
|
environment:
|
||||||
BITCOIN_EXTRA_ARGS: prune=50000
|
BITCOIN_EXTRA_ARGS: prune=50000
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
@@ -30,3 +30,5 @@ services:
|
|||||||
monacoind:
|
monacoind:
|
||||||
environment:
|
environment:
|
||||||
BITCOIN_EXTRA_ARGS: prune=25000
|
BITCOIN_EXTRA_ARGS: prune=25000
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
@@ -30,3 +30,5 @@ services:
|
|||||||
monacoind:
|
monacoind:
|
||||||
environment:
|
environment:
|
||||||
BITCOIN_EXTRA_ARGS: prune=5000
|
BITCOIN_EXTRA_ARGS: prune=5000
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
@@ -30,3 +30,5 @@ services:
|
|||||||
monacoind:
|
monacoind:
|
||||||
environment:
|
environment:
|
||||||
BITCOIN_EXTRA_ARGS: prune=100000
|
BITCOIN_EXTRA_ARGS: prune=100000
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
@@ -30,3 +30,5 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
BITCOIN_EXTRA_ARGS: |
|
BITCOIN_EXTRA_ARGS: |
|
||||||
txindex=1
|
txindex=1
|
||||||
|
exclusive:
|
||||||
|
- pruning
|
||||||
@@ -19,4 +19,9 @@ services:
|
|||||||
- btcpayserver
|
- btcpayserver
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
traefik_logs:
|
traefik_logs:
|
||||||
|
|
||||||
|
exclusive:
|
||||||
|
- proxy
|
||||||
|
required:
|
||||||
|
- "traefik"
|
||||||
17
docker-compose-generator/src/ConsoleUtils.cs
Normal file
17
docker-compose-generator/src/ConsoleUtils.cs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DockerGenerator
|
||||||
|
{
|
||||||
|
public static class ConsoleUtils
|
||||||
|
{
|
||||||
|
public static void WriteLine(string message, ConsoleColor color)
|
||||||
|
{
|
||||||
|
var old = Console.ForegroundColor;
|
||||||
|
Console.ForegroundColor = color;
|
||||||
|
Console.WriteLine(message);
|
||||||
|
Console.ForegroundColor = old;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,13 +10,13 @@ namespace DockerGenerator
|
|||||||
{
|
{
|
||||||
public class DockerComposeDefinition
|
public class DockerComposeDefinition
|
||||||
{
|
{
|
||||||
public HashSet<string> Fragments
|
public HashSet<FragmentName> Fragments
|
||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
private string _Name;
|
private string _Name;
|
||||||
|
|
||||||
public DockerComposeDefinition(string name, HashSet<string> fragments)
|
public DockerComposeDefinition(string name, HashSet<FragmentName> fragments)
|
||||||
{
|
{
|
||||||
Fragments = fragments;
|
Fragments = fragments;
|
||||||
_Name = name;
|
_Name = name;
|
||||||
@@ -30,6 +30,7 @@ namespace DockerGenerator
|
|||||||
{
|
{
|
||||||
get; set;
|
get; set;
|
||||||
}
|
}
|
||||||
|
public HashSet<FragmentName> ExcludeFragments { get; internal set; }
|
||||||
|
|
||||||
public string GetFilePath()
|
public string GetFilePath()
|
||||||
{
|
{
|
||||||
@@ -44,28 +45,33 @@ namespace DockerGenerator
|
|||||||
Console.WriteLine($"Generating {GetFilePath()}");
|
Console.WriteLine($"Generating {GetFilePath()}");
|
||||||
var deserializer = new DeserializerBuilder().Build();
|
var deserializer = new DeserializerBuilder().Build();
|
||||||
var serializer = new SerializerBuilder().Build();
|
var serializer = new SerializerBuilder().Build();
|
||||||
|
var fragmentsNotFound = new HashSet<FragmentName>();
|
||||||
|
var requiredFragments = new HashSet<FragmentName>();
|
||||||
|
var recommendedFragments = new HashSet<FragmentName>();
|
||||||
|
var processedFragments = new HashSet<FragmentName>();
|
||||||
|
var unprocessedFragments = new HashSet<FragmentName>();
|
||||||
|
var services = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||||
|
var volumes = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||||
|
var networks = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||||
|
var exclusives = new List<(FragmentName FragmentName, string Exclusivity)>();
|
||||||
|
|
||||||
Console.WriteLine($"With fragments:");
|
foreach (var fragment in Fragments.Where(NotExcluded))
|
||||||
foreach (var fragment in Fragments.ToList())
|
{
|
||||||
|
unprocessedFragments.Add(fragment);
|
||||||
|
}
|
||||||
|
reprocessFragments:
|
||||||
|
foreach (var fragment in unprocessedFragments)
|
||||||
{
|
{
|
||||||
var fragmentPath = GetFragmentLocation(fragment);
|
var fragmentPath = GetFragmentLocation(fragment);
|
||||||
if (!File.Exists(fragmentPath))
|
if (!File.Exists(fragmentPath))
|
||||||
{
|
{
|
||||||
Console.WriteLine($"\t{fragment} not found in {fragmentPath}, ignoring...");
|
fragmentsNotFound.Add(fragment);
|
||||||
Fragments.Remove(fragment);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Console.WriteLine($"\t{fragment}");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
foreach (var o in unprocessedFragments.Select(f => (f, ParseDocument(f))).ToList())
|
||||||
var services = new List<KeyValuePair<YamlNode, YamlNode>>();
|
|
||||||
var volumes = new List<KeyValuePair<YamlNode, YamlNode>>();
|
|
||||||
var networks = new List<KeyValuePair<YamlNode, YamlNode>>();
|
|
||||||
|
|
||||||
foreach (var doc in Fragments.Select(f => ParseDocument(f)))
|
|
||||||
{
|
{
|
||||||
|
var doc = o.Item2;
|
||||||
|
var fragment = o.f;
|
||||||
if (doc.Children.ContainsKey("services") && doc.Children["services"] is YamlMappingNode fragmentServicesRoot)
|
if (doc.Children.ContainsKey("services") && doc.Children["services"] is YamlMappingNode fragmentServicesRoot)
|
||||||
{
|
{
|
||||||
services.AddRange(fragmentServicesRoot.Children);
|
services.AddRange(fragmentServicesRoot.Children);
|
||||||
@@ -79,8 +85,57 @@ namespace DockerGenerator
|
|||||||
{
|
{
|
||||||
networks.AddRange(fragmentNetworksRoot.Children);
|
networks.AddRange(fragmentNetworksRoot.Children);
|
||||||
}
|
}
|
||||||
|
if (doc.Children.ContainsKey("exclusive") && doc.Children["exclusive"] is YamlSequenceNode fragmentExclusiveRoot)
|
||||||
|
{
|
||||||
|
foreach (var node in fragmentExclusiveRoot)
|
||||||
|
{
|
||||||
|
exclusives.Add((fragment, node.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (doc.Children.ContainsKey("required") && doc.Children["required"] is YamlSequenceNode fragmentRequireRoot)
|
||||||
|
{
|
||||||
|
foreach (var node in fragmentRequireRoot)
|
||||||
|
{
|
||||||
|
if (ExcludeFragments.Contains(new FragmentName(node.ToString())))
|
||||||
|
throw new YamlBuildException($"You excluded fragment {new FragmentName(node.ToString())} but it is required by {fragment}");
|
||||||
|
requiredFragments.Add(new FragmentName(node.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (doc.Children.ContainsKey("recommended") && doc.Children["recommended"] is YamlSequenceNode fragmentRecommendedRoot)
|
||||||
|
{
|
||||||
|
foreach (var node in fragmentRecommendedRoot)
|
||||||
|
{
|
||||||
|
if (!ExcludeFragments.Contains(new FragmentName(node.ToString())))
|
||||||
|
recommendedFragments.Add(new FragmentName(node.ToString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processedFragments.Add(fragment);
|
||||||
|
unprocessedFragments.Remove(fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var fragment in requiredFragments.Concat(recommendedFragments).Where(f => !processedFragments.Contains(f)))
|
||||||
|
{
|
||||||
|
unprocessedFragments.Add(fragment);
|
||||||
|
}
|
||||||
|
if (unprocessedFragments.Count != 0)
|
||||||
|
goto reprocessFragments;
|
||||||
|
|
||||||
|
var exclusiveConflict = exclusives.GroupBy(e => e.Exclusivity)
|
||||||
|
.Where(e => e.Count() != 1)
|
||||||
|
.FirstOrDefault();
|
||||||
|
if (exclusiveConflict != null)
|
||||||
|
throw new YamlBuildException($"The fragments {String.Join(", ", exclusiveConflict.Select(e => e.FragmentName))} can't be used simultaneously (group '{exclusiveConflict.Key}')");
|
||||||
|
|
||||||
|
Console.WriteLine($"Selected fragments:");
|
||||||
|
foreach (var fragment in processedFragments)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"\t{fragment}");
|
||||||
|
}
|
||||||
|
foreach (var fragment in fragmentsNotFound)
|
||||||
|
{
|
||||||
|
var fragmentPath = GetFragmentLocation(fragment);
|
||||||
|
ConsoleUtils.WriteLine($"\t{fragment} not found in {fragmentPath}, ignoring...", ConsoleColor.Yellow);
|
||||||
|
}
|
||||||
|
|
||||||
YamlMappingNode output = new YamlMappingNode();
|
YamlMappingNode output = new YamlMappingNode();
|
||||||
output.Add("version", new YamlScalarNode("3") { Style = YamlDotNet.Core.ScalarStyle.DoubleQuoted });
|
output.Add("version", new YamlScalarNode("3") { Style = YamlDotNet.Core.ScalarStyle.DoubleQuoted });
|
||||||
@@ -119,6 +174,11 @@ namespace DockerGenerator
|
|||||||
Console.WriteLine();
|
Console.WriteLine();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private bool NotExcluded(FragmentName arg)
|
||||||
|
{
|
||||||
|
return !ExcludeFragments.Contains(arg);
|
||||||
|
}
|
||||||
|
|
||||||
private void PostProcess(YamlMappingNode output)
|
private void PostProcess(YamlMappingNode output)
|
||||||
{
|
{
|
||||||
new BuildTimeVariableVisitor().Visit(output);
|
new BuildTimeVariableVisitor().Visit(output);
|
||||||
@@ -192,7 +252,7 @@ namespace DockerGenerator
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private YamlMappingNode ParseDocument(string fragment)
|
private YamlMappingNode ParseDocument(FragmentName fragment)
|
||||||
{
|
{
|
||||||
var input = new StringReader(File.ReadAllText(GetFragmentLocation(fragment)));
|
var input = new StringReader(File.ReadAllText(GetFragmentLocation(fragment)));
|
||||||
YamlStream stream = new YamlStream();
|
YamlStream stream = new YamlStream();
|
||||||
@@ -200,9 +260,9 @@ namespace DockerGenerator
|
|||||||
return (YamlMappingNode)stream.Documents[0].RootNode;
|
return (YamlMappingNode)stream.Documents[0].RootNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetFragmentLocation(string fragment)
|
private string GetFragmentLocation(FragmentName fragment)
|
||||||
{
|
{
|
||||||
return Path.Combine(FragmentLocation, $"{fragment}.yml");
|
return Path.Combine(FragmentLocation, $"{fragment.Name}.yml");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
49
docker-compose-generator/src/FragmentName.cs
Normal file
49
docker-compose-generator/src/FragmentName.cs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DockerGenerator
|
||||||
|
{
|
||||||
|
public class FragmentName
|
||||||
|
{
|
||||||
|
public FragmentName(string fragmentName)
|
||||||
|
{
|
||||||
|
if (fragmentName == null)
|
||||||
|
throw new ArgumentNullException(nameof(fragmentName));
|
||||||
|
Name = fragmentName.Trim().ToLowerInvariant();
|
||||||
|
if (Name.EndsWith(".yml", StringComparison.OrdinalIgnoreCase))
|
||||||
|
Name = Name.Substring(0, Name.Length - 4);
|
||||||
|
}
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
FragmentName item = obj as FragmentName;
|
||||||
|
if (item == null)
|
||||||
|
return false;
|
||||||
|
return Name.Equals(item.Name);
|
||||||
|
}
|
||||||
|
public static bool operator ==(FragmentName a, FragmentName b)
|
||||||
|
{
|
||||||
|
if (System.Object.ReferenceEquals(a, b))
|
||||||
|
return true;
|
||||||
|
if (((object)a == null) || ((object)b == null))
|
||||||
|
return false;
|
||||||
|
return a.Name == b.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(FragmentName a, FragmentName b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Name.GetHashCode();
|
||||||
|
}
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,7 +22,15 @@ namespace DockerGenerator
|
|||||||
|
|
||||||
var name = Environment.GetEnvironmentVariable("BTCPAYGEN_SUBNAME");
|
var name = Environment.GetEnvironmentVariable("BTCPAYGEN_SUBNAME");
|
||||||
name = string.IsNullOrEmpty(name) ? "generated" : name;
|
name = string.IsNullOrEmpty(name) ? "generated" : name;
|
||||||
new Program().Run(composition, name, generatedLocation);
|
try
|
||||||
|
{
|
||||||
|
new Program().Run(composition, name, generatedLocation);
|
||||||
|
}
|
||||||
|
catch (YamlBuildException ex)
|
||||||
|
{
|
||||||
|
ConsoleUtils.WriteLine(ex.Message, ConsoleColor.Red);
|
||||||
|
Environment.ExitCode = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Run(DockerComposition composition, string name, string output)
|
private void Run(DockerComposition composition, string name, string output)
|
||||||
@@ -35,13 +43,10 @@ namespace DockerGenerator
|
|||||||
switch (composition.SelectedProxy)
|
switch (composition.SelectedProxy)
|
||||||
{
|
{
|
||||||
case "nginx":
|
case "nginx":
|
||||||
fragments.Add("nginx-https");
|
|
||||||
fragments.Add("nginx");
|
fragments.Add("nginx");
|
||||||
fragments.Add("btcpayserver-nginx");
|
|
||||||
break;
|
break;
|
||||||
case "traefik":
|
case "traefik":
|
||||||
fragments.Add("traefik");
|
fragments.Add("traefik");
|
||||||
fragments.Add("traefik-labels");
|
|
||||||
break;
|
break;
|
||||||
case "no-reverseproxy":
|
case "no-reverseproxy":
|
||||||
case "none":
|
case "none":
|
||||||
@@ -50,9 +55,6 @@ namespace DockerGenerator
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
fragments.Add("btcpayserver");
|
fragments.Add("btcpayserver");
|
||||||
fragments.Add("opt-add-tor");
|
|
||||||
fragments.Add("nbxplorer");
|
|
||||||
fragments.Add("postgres");
|
|
||||||
foreach (var crypto in CryptoDefinition.GetDefinitions())
|
foreach (var crypto in CryptoDefinition.GetDefinitions())
|
||||||
{
|
{
|
||||||
if (!composition.SelectedCryptos.Contains(crypto.Crypto))
|
if (!composition.SelectedCryptos.Contains(crypto.Crypto))
|
||||||
@@ -71,10 +73,12 @@ namespace DockerGenerator
|
|||||||
|
|
||||||
foreach (var fragment in composition.AdditionalFragments)
|
foreach (var fragment in composition.AdditionalFragments)
|
||||||
{
|
{
|
||||||
fragments.Add(fragment.Trim());
|
fragments.Add(fragment);
|
||||||
}
|
}
|
||||||
fragments = fragments.Where(s => !composition.ExcludeFragments.Contains(s)).ToHashSet();
|
var def = new DockerComposeDefinition(name, fragments.Select(f => new FragmentName(f)).ToHashSet())
|
||||||
var def = new DockerComposeDefinition(name, fragments);
|
{
|
||||||
|
ExcludeFragments = composition.ExcludeFragments.Select(f => new FragmentName(f)).ToHashSet()
|
||||||
|
};
|
||||||
def.FragmentLocation = fragmentLocation;
|
def.FragmentLocation = fragmentLocation;
|
||||||
def.BuildOutputDirectory = output;
|
def.BuildOutputDirectory = output;
|
||||||
def.Build();
|
def.Build();
|
||||||
|
|||||||
@@ -10,7 +10,9 @@
|
|||||||
"BTCPAYGEN_CRYPTO3": "btg",
|
"BTCPAYGEN_CRYPTO3": "btg",
|
||||||
"BTCPAYGEN_CRYPTO2": "ltc",
|
"BTCPAYGEN_CRYPTO2": "ltc",
|
||||||
"BTCPAYGEN_CRYPTO1": "btc",
|
"BTCPAYGEN_CRYPTO1": "btc",
|
||||||
"BTCPAYGEN_REVERSEPROXY": "nginx"
|
"BTCPAYGEN_REVERSEPROXY": "nginx",
|
||||||
|
"BTCPAYGEN_ADDITIONAL_FRAGMENTS": "opt-save-storage",
|
||||||
|
"BTCPAYGEN_EXCLUDE_FRAGMENTS": "postgres"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
14
docker-compose-generator/src/YamlBuildException.cs
Normal file
14
docker-compose-generator/src/YamlBuildException.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DockerGenerator
|
||||||
|
{
|
||||||
|
public class YamlBuildException : Exception
|
||||||
|
{
|
||||||
|
public YamlBuildException(string message): base(message)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
<LangVersion>7.3</LangVersion>
|
||||||
<TargetFramework Condition="'$(TargetFrameworkOverride)' == ''">netcoreapp2.1</TargetFramework>
|
<TargetFramework Condition="'$(TargetFrameworkOverride)' == ''">netcoreapp2.1</TargetFramework>
|
||||||
<TargetFramework Condition="'$(TargetFrameworkOverride)' != ''">$(TargetFrameworkOverride)</TargetFramework>
|
<TargetFramework Condition="'$(TargetFrameworkOverride)' != ''">$(TargetFrameworkOverride)</TargetFramework>
|
||||||
<RootNamespace>DockerGenerator</RootNamespace>
|
<RootNamespace>DockerGenerator</RootNamespace>
|
||||||
|
|||||||
Reference in New Issue
Block a user