-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 7c6707f
Showing
29 changed files
with
1,182 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.vs/ | ||
bin/ | ||
obj/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
FROM microsoft/dotnet:sdk AS build | ||
|
||
ADD ./ /source | ||
|
||
WORKDIR /source | ||
|
||
RUN dotnet publish --configuration=Release | ||
|
||
FROM microsoft/dotnet:runtime | ||
|
||
COPY --from=build /source/PainlessGanttCli/bin/Release/netcoreapp2.0/publish /opt/PainlessGanttCli | ||
|
||
ENTRYPOINT ["dotnet", "/opt/PainlessGanttCli/PainlessGanttCli.dll"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
build: | ||
@docker container run \ | ||
--rm \ | ||
--interactive \ | ||
--tty \ | ||
-e UID=$(shell id --user $$USER) \ | ||
-e GID=$(shell id --group $$USER) \ | ||
-v $$PWD:$$PWD \ | ||
--workdir $$PWD \ | ||
microsoft/dotnet:sdk sh -c '\ | ||
dotnet publish --configuration=Release; \ | ||
chown -R $$UID:$$GID PainlessGantt/bin; \ | ||
chown -R $$UID:$$GID PainlessGantt/obj; \ | ||
chown -R $$UID:$$GID PainlessGanttCli/bin; \ | ||
chown -R $$UID:$$GID PainlessGanttCli/obj;' | ||
|
||
run: | ||
@[ -f PainlessGanttCli/bin/Release/netcoreapp2.0/publish/PainlessGanttCli.dll ] || make --no-print-directory build | ||
@docker container run \ | ||
--rm \ | ||
--interactive \ | ||
--tty \ | ||
-e UID=$(shell id --user $$USER) \ | ||
-e GID=$(shell id --group $$USER) \ | ||
-v $$PWD/PainlessGanttCli/bin/Release/netcoreapp2.0/publish:/publish:ro \ | ||
-v $$PWD/assets:/assets \ | ||
--workdir $$PWD \ | ||
microsoft/dotnet:runtime sh -c '\ | ||
dotnet /publish/PainlessGanttCli.dll \ | ||
--project /assets/project.yml \ | ||
--template /assets/template.xlsx \ | ||
--output /assets/ganttchart.xlsx; \ | ||
chown $$UID:$$GID /assets/ganttchart.xlsx;' | ||
|
||
format: | ||
@find . -type d \( \ | ||
-name .git -o \ | ||
-name .vs -o \ | ||
-name bin -o \ | ||
-name obj \ | ||
\) -prune -o -type f ! \( \ | ||
-name '*.xlsx' \ | ||
\) -print0 | xargs -0 dos2unix | ||
|
||
.PHONY: build run format |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio 15 | ||
VisualStudioVersion = 15.0.27004.2008 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PainlessGantt", "PainlessGantt\PainlessGantt.csproj", "{FBCF81F7-EFD5-4427-B1C4-953033F2B802}" | ||
EndProject | ||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PainlessGanttCli", "PainlessGanttCli\PainlessGanttCli.csproj", "{C411FB5C-6680-49D5-BE52-C47147CC1607}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{FBCF81F7-EFD5-4427-B1C4-953033F2B802}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{FBCF81F7-EFD5-4427-B1C4-953033F2B802}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{FBCF81F7-EFD5-4427-B1C4-953033F2B802}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{FBCF81F7-EFD5-4427-B1C4-953033F2B802}.Release|Any CPU.Build.0 = Release|Any CPU | ||
{C411FB5C-6680-49D5-BE52-C47147CC1607}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{C411FB5C-6680-49D5-BE52-C47147CC1607}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{C411FB5C-6680-49D5-BE52-C47147CC1607}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{C411FB5C-6680-49D5-BE52-C47147CC1607}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {0F58CC10-92A7-4015-A4A6-09547AB4BA0F} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace PainlessGantt.Construction | ||
{ | ||
/// <summary> | ||
/// <see cref="IConfiguration"/> インターフェイスの読み書き可能な実装を提供します。 | ||
/// </summary> | ||
public sealed class ConfigurationBuilder : IConfiguration | ||
{ | ||
/// <summary> | ||
/// 祝日の一覧を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "祝日")] | ||
public List<DateTime> Holidays { get; set; } = new List<DateTime>(); | ||
|
||
/// <inheritdoc /> | ||
IReadOnlyCollection<DateTime> IConfiguration.Holidays => Holidays; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
using System; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace PainlessGantt.Construction | ||
{ | ||
/// <summary> | ||
/// <see cref="IDateRange"/> インターフェイスの読み書き可能な実装を提供します。 | ||
/// </summary> | ||
public sealed class DateRangeBuilder : IDateRange | ||
{ | ||
/// <summary> | ||
/// 開始日を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "開始")] | ||
public DateTime Start { get; set; } | ||
|
||
/// <summary> | ||
/// 終了日を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "終了")] | ||
public DateTime End { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
using System.Collections.Generic; | ||
using JetBrains.Annotations; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace PainlessGantt.Construction | ||
{ | ||
/// <summary> | ||
/// <see cref="IGanttSource"/> インターフェイスの読み書き可能な実装を提供します。 | ||
/// </summary> | ||
public sealed class GanttSourceBuilder : IGanttSource | ||
{ | ||
/// <summary> | ||
/// このガント チャートの設定を取得または設定します。 | ||
/// </summary> | ||
[NotNull] | ||
[YamlMember(Alias = "設定")] | ||
public ConfigurationBuilder Configuration { get; set; } = new ConfigurationBuilder(); | ||
|
||
/// <inheritdoc /> | ||
IConfiguration IGanttSource.Configuration => Configuration; | ||
|
||
/// <summary> | ||
/// このガント チャートに含まれているプロジェクトの一覧を取得または設定します。 | ||
/// </summary> | ||
[ItemNotNull] | ||
[NotNull] | ||
[YamlMember(Alias = "プロジェクト一覧")] | ||
public List<ProjectBuilder> Projects { get; set; } = new List<ProjectBuilder>(); | ||
|
||
/// <inheritdoc /> | ||
IReadOnlyCollection<IProject> IGanttSource.Projects => Projects; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
using System.Collections.Generic; | ||
using JetBrains.Annotations; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace PainlessGantt.Construction | ||
{ | ||
/// <summary> | ||
/// <see cref="IProject"/> インターフェイスの読み書き可能な実装を提供します。 | ||
/// </summary> | ||
public sealed class ProjectBuilder : IProject | ||
{ | ||
/// <summary> | ||
/// このプロジェクトの名前を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "プロジェクト")] | ||
public string Name { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// このプロジェクトに含まれているチケットの一覧を取得または設定します。 | ||
/// </summary> | ||
[ItemNotNull] | ||
[NotNull] | ||
[YamlMember(Alias = "作業一覧")] | ||
public List<TicketBuilder> Tickets { get; set; } = new List<TicketBuilder>(); | ||
|
||
/// <inheritdoc /> | ||
IReadOnlyCollection<ITicket> IProject.Tickets => Tickets; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System.Collections.Generic; | ||
using JetBrains.Annotations; | ||
using YamlDotNet.Serialization; | ||
|
||
namespace PainlessGantt.Construction | ||
{ | ||
/// <summary> | ||
/// <see cref="ITicket"/> インターフェイスの読み書き可能な実装を提供します。 | ||
/// </summary> | ||
public sealed class TicketBuilder : ITicket | ||
{ | ||
/// <summary> | ||
/// このチケットの名前を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "作業")] | ||
public string Name { get; set; } = string.Empty; | ||
|
||
/// <summary> | ||
/// このチケットの消化に必要な見積もり期間を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "予定")] | ||
public DateRangeBuilder EstimatedPeriod { get; set; } = new DateRangeBuilder(); | ||
|
||
/// <inheritdoc /> | ||
IDateRange ITicket.EstimatedPeriod => EstimatedPeriod; | ||
|
||
/// <summary> | ||
/// このチケットの消化にかかった実際の期間を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "実績")] | ||
public DateRangeBuilder ActualPeriod { get; set; } = new DateRangeBuilder(); | ||
|
||
/// <inheritdoc /> | ||
IDateRange ITicket.ActualPeriod => ActualPeriod; | ||
|
||
/// <summary> | ||
/// このチケットの現状の状態を取得または設定します。 | ||
/// </summary> | ||
[YamlMember(Alias = "状態")] | ||
public TicketStatus Status { get; set; } = TicketStatus.Unknown; | ||
|
||
/// <summary> | ||
/// このチケットの子チケットを取得または設定します。 | ||
/// </summary> | ||
[ItemNotNull] | ||
[NotNull] | ||
[YamlMember(Alias = "詳細")] | ||
public List<TicketBuilder> Children { get; set; } = new List<TicketBuilder>(); | ||
|
||
/// <inheritdoc /> | ||
IReadOnlyCollection<ITicket> ITicket.Children => Children; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using JetBrains.Annotations; | ||
|
||
namespace PainlessGantt | ||
{ | ||
/// <summary> | ||
/// <see cref="IDateRange"/> インターフェイスを拡張します。 | ||
/// </summary> | ||
public static class DateRangeExtension | ||
{ | ||
/// <summary> | ||
/// 指定した日付の範囲に含まれている日を列挙します。 | ||
/// </summary> | ||
/// <param name="range">日付の範囲。</param> | ||
/// <returns><paramref name="range"/> に含まれているすべての日を順番に含むシーケンス。</returns> | ||
/// <exception cref="ArgumentNullException"><paramref name="range"/> が <c>null</c> です。</exception> | ||
[LinqTunnel] | ||
[NotNull] | ||
public static IEnumerable<DateTime> AsEnumerable([NotNull] this IDateRange range) | ||
{ | ||
if (range == null) | ||
throw new ArgumentNullException(nameof(range)); | ||
var daysInRange = (range.End - range.Start).Days + 1; | ||
return Enumerable.Range(0, daysInRange).Select(x => range.Start.AddDays(x)); | ||
} | ||
|
||
/// <summary> | ||
/// 指定した日が範囲内かどうかを判断します。 | ||
/// </summary> | ||
/// <param name="range">日付の範囲。</param> | ||
/// <param name="date">範囲内かどうかを判断する対象の日。</param> | ||
/// <returns><paramref name="date"/> が <paramref name="range"/> の範囲内の場合は <c>true</c>。それ以外の場合は <c>false</c>。</returns> | ||
public static bool In([NotNull] this IDateRange range, DateTime date) | ||
{ | ||
if (range == null) | ||
throw new ArgumentNullException(nameof(range)); | ||
if (range.Start == default || range.End == default) | ||
return false; | ||
return range.Start <= date && date <= range.End; | ||
} | ||
|
||
/// <summary> | ||
/// 指定した <see cref="IDateRange"/> のシーケンスに含まれている日付の最小値を取得します。 | ||
/// </summary> | ||
/// <param name="source"><see cref="IDateRange"/> のシーケンス。</param> | ||
/// <returns><paramref name="source"/> に含まれている日付の最小値。</returns> | ||
/// <exception cref="ArgumentNullException"><paramref name="source"/> が <c>null</c> です。</exception> | ||
public static DateTime Minimum([ItemNotNull] [NotNull] this IEnumerable<IDateRange> source) | ||
{ | ||
if (source == null) | ||
throw new ArgumentNullException(nameof(source)); | ||
return source.Where(x => x.Start != default).Select(x => x.Start).DefaultIfEmpty().Min(); | ||
} | ||
|
||
/// <summary> | ||
/// 指定した <see cref="IDateRange"/> のシーケンスに含まれている日付の最大値を取得します。 | ||
/// </summary> | ||
/// <param name="source"><see cref="IDateRange"/> のシーケンス。</param> | ||
/// <returns><paramref name="source"/> に含まれている日付の最大値。</returns> | ||
/// <exception cref="ArgumentNullException"><paramref name="source"/> が <c>null</c> です。</exception> | ||
public static DateTime Maximum([ItemNotNull] [NotNull] this IEnumerable<IDateRange> source) | ||
{ | ||
if (source == null) | ||
throw new ArgumentNullException(nameof(source)); | ||
return source.Where(x => x.End != default).Select(x => x.End).DefaultIfEmpty().Max(); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
using System; | ||
using System.Collections.Concurrent; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using JetBrains.Annotations; | ||
|
||
namespace PainlessGantt | ||
{ | ||
/// <summary> | ||
/// 列挙体のフィールドをユーザーに表示する際の表示名を定義します。 | ||
/// </summary> | ||
[AttributeUsage(AttributeTargets.Field)] | ||
public sealed class EnumDisplayNameAttribute : Attribute | ||
{ | ||
[NotNull] | ||
private static readonly ConcurrentDictionary<Type, Dictionary<string, string>> _cache = new ConcurrentDictionary<Type, Dictionary<string, string>>(); | ||
|
||
/// <summary> | ||
/// 指定した列挙値に関連付けられている <see cref="DisplayName"/> を取得します。 | ||
/// </summary> | ||
/// <typeparam name="TEnum"><see cref="EnumDisplayNameAttribute"/> 属性が宣言された列挙体の型。</typeparam> | ||
/// <param name="value"><typeparamref name="TEnum"/> 型の列挙値。</param> | ||
/// <returns><paramref name="value"/> に関連付けられている <see cref="DisplayName"/>。</returns> | ||
/// <exception cref="ArgumentException"> | ||
/// <paramref name="value"/> が列挙体ではありません。 | ||
/// または、<paramref name="value"/> に関連付けられている <see cref="EnumDisplayNameAttribute"/> 属性が見つかりませんでした。 | ||
/// </exception> | ||
[NotNull] | ||
public static string GetDisplayName<TEnum>(TEnum value) | ||
where TEnum : struct | ||
{ | ||
var index = _cache.GetOrAdd(typeof(TEnum), type => type | ||
.GetFields(BindingFlags.Public | BindingFlags.Static) | ||
.Select(x => (name: x.Name, attribute: x.GetCustomAttribute<EnumDisplayNameAttribute>())) | ||
.ToDictionary(x => x.name, x => x.attribute.DisplayName)); | ||
var fieldName = Enum.GetName(typeof(TEnum), value); | ||
if (fieldName == null) | ||
throw new ArgumentException("列挙値ではありません。"); | ||
if (!index.TryGetValue(fieldName, out var displayName)) | ||
throw new FormatException($"列挙値に関連付けられている {nameof(EnumDisplayNameAttribute)} 属性が見つかりませんでした。"); | ||
return displayName; | ||
} | ||
|
||
/// <summary> | ||
/// <see cref="EnumDisplayNameAttribute"/> クラスの新しいインスタンスを初期化します。 | ||
/// </summary> | ||
/// <param name="displayName">列挙体の表示名。</param> | ||
/// <exception cref="ArgumentNullException"><paramref name="displayName"/> が <c>null</c> です。</exception> | ||
internal EnumDisplayNameAttribute([NotNull] string displayName) | ||
{ | ||
DisplayName = displayName ?? throw new ArgumentNullException(nameof(displayName)); | ||
} | ||
|
||
/// <summary> | ||
/// 列挙体の表示名を取得します。 | ||
/// </summary> | ||
[NotNull] | ||
public string DisplayName { get; } | ||
} | ||
} |
Oops, something went wrong.