|
@@ -2,8 +2,10 @@
|
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
|
using System.ComponentModel;
|
|
using System.ComponentModel;
|
|
|
using System.ComponentModel.Design;
|
|
using System.ComponentModel.Design;
|
|
|
|
|
+using System.IO;
|
|
|
using System.IO.Abstractions;
|
|
using System.IO.Abstractions;
|
|
|
using System.Linq;
|
|
using System.Linq;
|
|
|
|
|
+using System.Threading;
|
|
|
using BO.AppServer.Metadata.Dto;
|
|
using BO.AppServer.Metadata.Dto;
|
|
|
using BO.AppServer.Metadata.Enums;
|
|
using BO.AppServer.Metadata.Enums;
|
|
|
using BO.Console.Commands.Base;
|
|
using BO.Console.Commands.Base;
|
|
@@ -11,11 +13,13 @@ using BO.Console.Commands.Workspace.Sync;
|
|
|
using BO.Console.Commands.Workspace.Sync.Diff;
|
|
using BO.Console.Commands.Workspace.Sync.Diff;
|
|
|
using Quadarax.Foundation.Core.Data.Diff;
|
|
using Quadarax.Foundation.Core.Data.Diff;
|
|
|
using Quadarax.Foundation.Core.IO;
|
|
using Quadarax.Foundation.Core.IO;
|
|
|
|
|
+using Quadarax.Foundation.Core.IO.Extensions;
|
|
|
using Quadarax.Foundation.Core.QConsole;
|
|
using Quadarax.Foundation.Core.QConsole;
|
|
|
using Quadarax.Foundation.Core.QConsole.Argument;
|
|
using Quadarax.Foundation.Core.QConsole.Argument;
|
|
|
using Quadarax.Foundation.Core.QConsole.Attributes;
|
|
using Quadarax.Foundation.Core.QConsole.Attributes;
|
|
|
using Quadarax.Foundation.Core.QConsole.Value;
|
|
using Quadarax.Foundation.Core.QConsole.Value;
|
|
|
using Quadarax.Foundation.Core.Value;
|
|
using Quadarax.Foundation.Core.Value;
|
|
|
|
|
+using Quadarax.Foundation.Core.Value.Extensions;
|
|
|
|
|
|
|
|
namespace BO.Console.Commands.Workspace
|
|
namespace BO.Console.Commands.Workspace
|
|
|
{
|
|
{
|
|
@@ -33,7 +37,7 @@ namespace BO.Console.Commands.Workspace
|
|
|
"\t\t...\n" +
|
|
"\t\t...\n" +
|
|
|
"[" +CS_NEW_OUT + "]\t- new artifacts directory for Output type\n" +
|
|
"[" +CS_NEW_OUT + "]\t- new artifacts directory for Output type\n" +
|
|
|
"[<documentId:8>.<document_name_normalized>]\t- document directory\n" +
|
|
"[<documentId:8>.<document_name_normalized>]\t- document directory\n" +
|
|
|
- "\t\t<arifact_id>.<artifact_type>.<artifact_name>.<artifaxt_ext> - artifact file\n" +
|
|
|
|
|
|
|
+ "\t\t<arifact_id:8>.<artifact_type>.<artifact_name>.<artifaxt_ext> - artifact file\n" +
|
|
|
"\t\t...\n" +
|
|
"\t\t...\n" +
|
|
|
"...\n" +
|
|
"...\n" +
|
|
|
"\n" +
|
|
"\n" +
|
|
@@ -71,6 +75,7 @@ namespace BO.Console.Commands.Workspace
|
|
|
private const string CS_ARG_HINT_INT = "<repeat_interval>";
|
|
private const string CS_ARG_HINT_INT = "<repeat_interval>";
|
|
|
private const string CS_ARG_DESC_INT = "Timespan interval between two iterations. Default is 00:30:00.";
|
|
private const string CS_ARG_DESC_INT = "Timespan interval between two iterations. Default is 00:30:00.";
|
|
|
|
|
|
|
|
|
|
+ private const string CS_ARG_DESC_USER = "If defined, gets APIKey and password from defined user default workspace, otherwise use APIkey from argument or configuration.";
|
|
|
|
|
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
|
@@ -103,20 +108,38 @@ namespace BO.Console.Commands.Workspace
|
|
|
protected override Result OnExecute()
|
|
protected override Result OnExecute()
|
|
|
{
|
|
{
|
|
|
|
|
|
|
|
-
|
|
|
|
|
bool isExitSignal = false;
|
|
bool isExitSignal = false;
|
|
|
int nCnt = 0;
|
|
int nCnt = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (!string.IsNullOrEmpty(UserName))
|
|
|
|
|
+ {
|
|
|
|
|
+ WriteDebugInfo($"Getting default workspace info for user '{UserName}'");
|
|
|
|
|
+ var workspaces = Client.GetWorkspacesAsync(WorkspaceScopeEnums.MyDefault, UserName).Result;
|
|
|
|
|
+ if (!workspaces.Any())
|
|
|
|
|
+ throw new Exception($"No default workspace for user '{UserName}' set.");
|
|
|
|
|
+ var userWorkspace = workspaces.First();
|
|
|
|
|
+ WriteInfo($"User has default workspace named '{userWorkspace.Name}' [{userWorkspace.Id}] (Created:{userWorkspace.Audit.Created.ToFileShortDateTimeString()}, Changed:{userWorkspace.Audit.Changed?.ToFileShortDateTimeString()})");
|
|
|
|
|
+ WriteCaption($"Using APIKey: {userWorkspace.ApiKeyNormalized}");
|
|
|
|
|
+ SetApiKey(userWorkspace.ApiKeyNormalized, userWorkspace.Apipassword);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ var workspace = Client.GetWorkspaceAsync(WorkspaceIdentificationTypeEnum.ApiKey, ApiKey).Result;
|
|
|
|
|
+ if (workspace == null)
|
|
|
|
|
+ return new Result(new Exception($"Workspace with API-KEY: {ApiKey} not found."));
|
|
|
|
|
+ var dirInfo = OpenDirectory(workspace);
|
|
|
|
|
+
|
|
|
|
|
+ var iteration = 0;
|
|
|
|
|
+
|
|
|
while (!isExitSignal)
|
|
while (!isExitSignal)
|
|
|
{
|
|
{
|
|
|
if (!IsRepeat)
|
|
if (!IsRepeat)
|
|
|
isExitSignal = true;
|
|
isExitSignal = true;
|
|
|
|
|
|
|
|
- var workspace = Client.GetWorkspaceAsync(WorkspaceIdentificationTypeEnum.ApiKey, ApiKey).Result;
|
|
|
|
|
- if (workspace == null)
|
|
|
|
|
- return new Result(new Exception($"Workspace with API-KEY: {ApiKey} not found."));
|
|
|
|
|
- var documents = Client.GetWorkspaceDocumentsAsync(DocumentsScopeEnums.All, ApiKey, ApiKeyPassword, UserName).Result;
|
|
|
|
|
- var dirInfo = OpenDirectory(workspace);
|
|
|
|
|
|
|
+ WriteInfo($"Iteration {iteration} started.");
|
|
|
|
|
|
|
|
|
|
+ var documents = Client.GetWorkspaceDocumentsAsync(DocumentsScopeEnums.All, ApiKey, ApiKeyPassword, UserName).Result;
|
|
|
|
|
+
|
|
|
var factory = new DocumentEntryComparer();
|
|
var factory = new DocumentEntryComparer();
|
|
|
foreach (var dir in dirInfo.EnumerateDirectories())
|
|
foreach (var dir in dirInfo.EnumerateDirectories())
|
|
|
{
|
|
{
|
|
@@ -164,22 +187,26 @@ namespace BO.Console.Commands.Workspace
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var diff = factory.GetComparator();
|
|
var diff = factory.GetComparator();
|
|
|
- var locals = diff.CompareLeftSide().Where(x => x.CompareState != DiffEntry.CompareStateEnum.Equals);
|
|
|
|
|
|
|
+ var locals = diff.CompareRightSide().Where(x => x.CompareState != DiffEntry.CompareStateEnum.Equals);
|
|
|
foreach (var local in locals)
|
|
foreach (var local in locals)
|
|
|
{
|
|
{
|
|
|
var item = local.GetItem<DocumentItem>();
|
|
var item = local.GetItem<DocumentItem>();
|
|
|
if (local.CompareState == DiffEntry.CompareStateEnum.CurrentNull ||
|
|
if (local.CompareState == DiffEntry.CompareStateEnum.CurrentNull ||
|
|
|
local.CompareState == DiffEntry.CompareStateEnum.CurrentSmaller)
|
|
local.CompareState == DiffEntry.CompareStateEnum.CurrentSmaller)
|
|
|
{
|
|
{
|
|
|
- WriteInfo($"Artifact '{item.ArtName}' will be downloaded");
|
|
|
|
|
|
|
+ WriteInfo($"Artifact '{item.ArtName}' will be uploaded");
|
|
|
|
|
+
|
|
|
}
|
|
}
|
|
|
else if (local.CompareState == DiffEntry.CompareStateEnum.CurrentGrater ||
|
|
else if (local.CompareState == DiffEntry.CompareStateEnum.CurrentGrater ||
|
|
|
local.CompareState == DiffEntry.CompareStateEnum.OtherNull)
|
|
local.CompareState == DiffEntry.CompareStateEnum.OtherNull)
|
|
|
{
|
|
{
|
|
|
- WriteInfo($"Artifact '{item.ArtName}' will be uploaded");
|
|
|
|
|
|
|
+ WriteInfo($"Artifact '{item.ArtName}' will be downloaded");
|
|
|
|
|
+ DownloadArtifact(dirInfo, item);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ if (IsRepeat)
|
|
|
|
|
+ Thread.CurrentThread.Join(Interval);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -228,6 +255,53 @@ namespace BO.Console.Commands.Workspace
|
|
|
return di;
|
|
return di;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+ private void DownloadArtifact(IDirectoryInfo outputDir, DocumentItem artifactItem)
|
|
|
|
|
+ {
|
|
|
|
|
+ if (outputDir == null)
|
|
|
|
|
+ throw new ArgumentNullException(nameof(outputDir));
|
|
|
|
|
+ if (artifactItem == null)
|
|
|
|
|
+ throw new ArgumentNullException(nameof(artifactItem));
|
|
|
|
|
+ var currentDir = outputDir;
|
|
|
|
|
+ using (var artFs = Client.GetWorkspaceDocumentContentAsync(ApiKey, ApiKeyPassword,
|
|
|
|
|
+ artifactItem.DocId.GetValueOrDefault(), artifactItem.ArtId.GetValueOrDefault(),string.Empty).Result)
|
|
|
|
|
+ {
|
|
|
|
|
+ long fileSize = 0;
|
|
|
|
|
+ var fileName = GetArtifactPhysicalFileName(artifactItem);
|
|
|
|
|
+ var dirName = GetDocumentPhysicalDirName(artifactItem);
|
|
|
|
|
+ currentDir = currentDir.GetDirectory(dirName) ?? outputDir.CreateSubdirectory(dirName);
|
|
|
|
|
+ using (var outFs = currentDir.CreateFile(fileName))
|
|
|
|
|
+ {
|
|
|
|
|
+ //CopyStream(artFs, outFs);
|
|
|
|
|
+ artFs.CopyTo(outFs);
|
|
|
|
|
+ outFs.Flush();
|
|
|
|
|
+ fileSize = outFs.Length;
|
|
|
|
|
+ }
|
|
|
|
|
+ WriteInfo($"{fileName} downloaded [{artifactItem.ArtLength}/{fileSize} bytes]");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ public static void CopyStream(Stream input, Stream output)
|
|
|
|
|
+ {
|
|
|
|
|
+ byte[] buffer = new byte[16 * 1024];
|
|
|
|
|
+ int read;
|
|
|
|
|
+ while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
|
|
|
|
|
+ {
|
|
|
|
|
+ output.Write(buffer, 0, read);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ private string GetArtifactPhysicalFileName(DocumentItem artifactItem)
|
|
|
|
|
+ {
|
|
|
|
|
+ //<arifact_id:8>.<artifact_type>.<artifact_name>.<artifaxt_ext> - artifact file
|
|
|
|
|
+ return $"{artifactItem.ArtId.GetValueOrDefault():D8}.{artifactItem.ArtType}.{FileUtils.SanitizedFileName(FileSystem,artifactItem.ArtName)}{artifactItem.ArtExt}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ private string GetDocumentPhysicalDirName(DocumentItem documentItem)
|
|
|
|
|
+ {
|
|
|
|
|
+ //[<documentId:8>.<document_name_normalized>]
|
|
|
|
|
+ return $"{documentItem.DocId.GetValueOrDefault():D8}.{FileUtils.SanitizedFileName(FileSystem, documentItem.DocName)}";
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
|
|
#region *** Private operations ***
|
|
#region *** Private operations ***
|
|
@@ -251,6 +325,7 @@ namespace BO.Console.Commands.Workspace
|
|
|
args.Add(new NamedArgument(CS_ARG_NAME_INT, CS_ARG_DESC_INT, CS_ARG_HINT_INT, TypeValuesEnum.TimeSpan, TimeSpan.FromSeconds(30).ToString(), false));
|
|
args.Add(new NamedArgument(CS_ARG_NAME_INT, CS_ARG_DESC_INT, CS_ARG_HINT_INT, TypeValuesEnum.TimeSpan, TimeSpan.FromSeconds(30).ToString(), false));
|
|
|
args.Add(new FlagArgument(CS_ARG_NAME_DELETE, CS_ARG_DESC_DELETE, CS_ARG_HINT_DELETE, false));
|
|
args.Add(new FlagArgument(CS_ARG_NAME_DELETE, CS_ARG_DESC_DELETE, CS_ARG_HINT_DELETE, false));
|
|
|
args.Add(new FlagArgument(CS_ARG_NAME_INIT, CS_ARG_DESC_INIT, CS_ARG_HINT_INIT, false));
|
|
args.Add(new FlagArgument(CS_ARG_NAME_INIT, CS_ARG_DESC_INIT, CS_ARG_HINT_INIT, false));
|
|
|
|
|
+ AppendUserArgument(args, CS_ARG_DESC_USER);
|
|
|
return args;
|
|
return args;
|
|
|
}
|
|
}
|
|
|
|
|
|