Browse Source

Merge branch 'dev' of github.com:abpframework/abp into feat/improve-linked-list-types

pull/3428/head
Arman Ozak 6 years ago
parent
commit
be743b9375
  1. 21
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs
  2. 76
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ConnectionStringChangeStep.cs
  3. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs
  4. 7
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs
  5. 61
      framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs
  6. 37
      framework/src/Volo.Abp.Core/Volo/Abp/Text/StringHelper.cs
  7. 1
      npm/ng-packs/package.json
  8. 1532
      npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts
  9. 1
      npm/ng-packs/packages/core/src/lib/utils/index.ts
  10. 396
      npm/ng-packs/packages/core/src/lib/utils/linked-list.ts

21
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Commands/NewCommand.cs

@ -73,6 +73,12 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation("UI Framework: " + uiFramework);
}
var connectionString = GetConnectionString(commandLineArgs);
if (connectionString != null)
{
Logger.LogInformation("Connection string: " + connectionString);
}
var mobileApp = GetMobilePreference(commandLineArgs);
if (mobileApp != MobileApp.None)
{
@ -122,7 +128,8 @@ namespace Volo.Abp.Cli.Commands
mobileApp,
gitHubLocalRepositoryPath,
templateSource,
commandLineArgs.Options
commandLineArgs.Options,
connectionString
)
);
@ -168,6 +175,12 @@ namespace Volo.Abp.Cli.Commands
Logger.LogInformation($"'{projectName}' has been successfully created to '{outputFolder}'");
}
private static string GetConnectionString(CommandLineArgs commandLineArgs)
{
var connectionString = commandLineArgs.Options.GetOrNull(Options.ConnectionString.Short, Options.ConnectionString.Long);
return string.IsNullOrWhiteSpace(connectionString) ? null : connectionString;
}
public string GetUsageInfo()
{
var sb = new StringBuilder();
@ -309,6 +322,12 @@ namespace Volo.Abp.Cli.Commands
public const string Long = "template-source";
}
public static class ConnectionString
{
public const string Short = "cs";
public const string Long = "connection-string";
}
public static class CreateSolutionFolder
{
public const string Short = "csf";

76
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/Steps/ConnectionStringChangeStep.cs

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Volo.Abp.Cli.ProjectBuilding.Files;
using Volo.Abp.Text;
namespace Volo.Abp.Cli.ProjectBuilding.Building.Steps
{
public class ConnectionStringChangeStep : ProjectBuildPipelineStep
{
private const string DefaultConnectionStringKey = "Default";
public override void Execute(ProjectBuildContext context)
{
var appSettingsJsonFiles = context.Files.Where(f =>
f.Name.EndsWith("appsettings.json", StringComparison.OrdinalIgnoreCase))
.ToArray();
if (!appSettingsJsonFiles.Any())
{
return;
}
var newConnectionString = $"\"{DefaultConnectionStringKey}\": \"{context.BuildArgs.ConnectionString}\"";
foreach (var appSettingsJson in appSettingsJsonFiles)
{
try
{
var appSettingJsonContentWithoutBom = StringHelper.ConvertFromBytesWithoutBom(appSettingsJson.Bytes);
var jsonObject = JObject.Parse(appSettingJsonContentWithoutBom);
var connectionStringContainer = (JContainer)jsonObject?["ConnectionStrings"];
if (connectionStringContainer == null)
{
continue;
}
if (!connectionStringContainer.Any())
{
continue;
}
var connectionStrings = connectionStringContainer.ToList();
foreach (var connectionString in connectionStrings)
{
var property = ((JProperty)connectionString);
var connectionStringName = property.Name;
if (connectionStringName == DefaultConnectionStringKey)
{
var defaultConnectionString = property.ToString();
if (defaultConnectionString == null)
{
continue;
}
appSettingsJson.ReplaceText(defaultConnectionString, newConnectionString);
break;
}
}
}
catch (Exception ex)
{
Console.WriteLine("Cannot change the connection string in " + appSettingsJson.Name + ". Error: " + ex.Message);
}
}
}
}
}

5
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/Building/TemplateProjectBuildPipelineBuilder.cs

@ -28,6 +28,11 @@ namespace Volo.Abp.Cli.ProjectBuilding.Building
pipeline.Steps.Add(new RemoveRootFolderStep());
}
if (context.BuildArgs.ConnectionString != null)
{
pipeline.Steps.Add(new ConnectionStringChangeStep());
}
pipeline.Steps.Add(new CreateProjectResultZipStep());
return pipeline;

7
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/ProjectBuildArgs.cs

@ -27,6 +27,9 @@ namespace Volo.Abp.Cli.ProjectBuilding
[CanBeNull]
public string TemplateSource { get; set; }
[CanBeNull]
public string ConnectionString { get; set; }
[NotNull]
public Dictionary<string, string> ExtraProperties { get; set; }
@ -39,7 +42,8 @@ namespace Volo.Abp.Cli.ProjectBuilding
MobileApp? mobileApp = null,
[CanBeNull] string abpGitHubLocalRepositoryPath = null,
[CanBeNull] string templateSource = null,
Dictionary<string, string> extraProperties = null)
Dictionary<string, string> extraProperties = null,
[CanBeNull] string connectionString = null)
{
SolutionName = Check.NotNull(solutionName, nameof(solutionName));
TemplateName = templateName;
@ -50,6 +54,7 @@ namespace Volo.Abp.Cli.ProjectBuilding
AbpGitHubLocalRepositoryPath = abpGitHubLocalRepositoryPath;
TemplateSource = templateSource;
ExtraProperties = extraProperties ?? new Dictionary<string, string>();
ConnectionString = connectionString;
}
}
}

61
framework/src/Volo.Abp.Core/Volo/Abp/IO/FileHelper.cs

@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Volo.Abp.Text;
namespace Volo.Abp.IO
{
@ -73,6 +75,63 @@ namespace Volo.Abp.IO
}
}
//TODO: ReadAllLinesAsync
/// <summary>
/// Opens a text file, reads all lines of the file, and then closes the file.
/// </summary>
/// <param name="path">The file to open for reading.</param>
/// <param name="encoding">Encoding of the file. Default is UTF8</param>
/// <param name="fileMode">Specifies how the operating system should open a file. Default is Open</param>
/// <param name="fileAccess">Defines constants for read, write, or read/write access to a file. Default is Read</param>
/// <param name="fileShare">Contains constants for controlling the kind of access other FileStream objects can have to the same file. Default is Read</param>
/// <param name="bufferSize">Length of StreamReader buffer. Default is 4096.</param>
/// <param name="fileOptions">Indicates FileStream options. Default is Asynchronous (The file is to be used for asynchronous reading.) and SequentialScan (The file is to be accessed sequentially from beginning to end.) </param>
/// <returns>A string containing all lines of the file.</returns>
public static async Task<string[]> ReadAllLinesAsync(string path,
Encoding encoding = null,
FileMode fileMode = FileMode.Open,
FileAccess fileAccess = FileAccess.Read,
FileShare fileShare = FileShare.Read,
int bufferSize = 4096,
FileOptions fileOptions = FileOptions.Asynchronous | FileOptions.SequentialScan)
{
if (encoding == null)
{
encoding = Encoding.UTF8;
}
var lines = new List<string>();
using (var stream = new FileStream(
path,
fileMode,
fileAccess,
fileShare,
bufferSize,
fileOptions))
{
using (var reader = new StreamReader(stream, encoding))
{
string line;
while ((line = await reader.ReadLineAsync()) != null)
{
lines.Add(line);
}
}
}
return lines.ToArray();
}
/// <summary>
/// Opens a text file, reads content without BOM
/// </summary>
/// <param name="path">The file to open for reading.</param>
/// <returns>A string containing all lines of the file.</returns>
public static async Task<string> ReadFileWithoutBomAsync(string path)
{
var content = await ReadAllBytesAsync(path);
return StringHelper.ConvertFromBytesWithoutBom(content);
}
}
}

37
framework/src/Volo.Abp.Core/Volo/Abp/Text/StringHelper.cs

@ -0,0 +1,37 @@
using System.Text;
namespace Volo.Abp.Text
{
public class StringHelper
{
/// <summary>
/// Converts a byte[] to string without BOM (byte order mark).
/// </summary>
/// <param name="bytes">The byte[] to be converted to string</param>
/// <param name="encoding">The encoding to get string. Default is UTF8</param>
/// <returns></returns>
public static string ConvertFromBytesWithoutBom(byte[] bytes, Encoding encoding = null)
{
if (bytes == null)
{
return null;
}
if (encoding == null)
{
encoding = Encoding.UTF8;
}
var hasBom = bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF;
if (hasBom)
{
return encoding.GetString(bytes, 3, bytes.Length - 3);
}
else
{
return encoding.GetString(bytes);
}
}
}
}

1
npm/ng-packs/package.json

@ -77,7 +77,6 @@
"ngxs-reset-plugin": "^1.2.0",
"ngxs-schematic": "^1.1.9",
"prettier": "^1.18.2",
"primeicons": "^2.0.0",
"protractor": "~5.4.0",
"rxjs": "~6.4.0",
"snq": "^1.0.3",

1532
npm/ng-packs/packages/core/src/lib/tests/linked-list.spec.ts

File diff suppressed because it is too large

1
npm/ng-packs/packages/core/src/lib/utils/index.ts

@ -1,6 +1,5 @@
export * from './common-utils';
export * from './generator-utils';
export * from './initial-utils';
export * from './linked-list';
export * from './route-utils';
export * from './rxjs-utils';

396
npm/ng-packs/packages/core/src/lib/utils/linked-list.ts

@ -1,396 +0,0 @@
/* tslint:disable:no-non-null-assertion */
import compare from 'just-compare';
export class ListNode<T = any> {
readonly value: T;
next: ListNode | undefined;
previous: ListNode | undefined;
constructor(value: T) {
this.value = value;
}
}
export class LinkedList<T = any> {
private first: ListNode<T> | undefined;
private last: ListNode<T> | undefined;
private size = 0;
get head(): ListNode<T> | undefined {
return this.first;
}
get tail(): ListNode<T> | undefined {
return this.last;
}
get length(): number {
return this.size;
}
private attach(
value: T,
previousNode: ListNode<T> | undefined,
nextNode: ListNode<T> | undefined,
): ListNode<T> {
if (!previousNode) return this.addHead(value);
if (!nextNode) return this.addTail(value);
const node = new ListNode(value);
node.previous = previousNode;
previousNode.next = node;
node.next = nextNode;
nextNode.previous = node;
this.size++;
return node;
}
private attachMany(
values: T[],
previousNode: ListNode<T> | undefined,
nextNode: ListNode<T> | undefined,
): ListNode<T>[] {
if (!values.length) return [];
if (!previousNode) return this.addManyHead(values);
if (!nextNode) return this.addManyTail(values);
const list = new LinkedList<T>();
list.addManyTail(values);
list.first!.previous = previousNode;
previousNode.next = list.first;
list.last!.next = nextNode;
nextNode.previous = list.last;
this.size += values.length;
return list.toNodeArray();
}
private detach(node: ListNode<T>) {
if (!node.previous) return this.dropHead();
if (!node.next) return this.dropTail();
node.previous.next = node.next;
node.next.previous = node.previous;
this.size--;
return node;
}
add(value: T) {
return {
after: (previousValue: T, compareFn: ListComparisonFn<T> = compare) =>
this.addAfter(value, previousValue, compareFn),
before: (nextValue: T, compareFn: ListComparisonFn<T> = compare) =>
this.addBefore(value, nextValue, compareFn),
byIndex: (position: number) => this.addByIndex(value, position),
head: () => this.addHead(value),
tail: () => this.addTail(value),
};
}
addMany(values: T[]) {
return {
after: (previousValue: T, compareFn: ListComparisonFn<T> = compare) =>
this.addManyAfter(values, previousValue, compareFn),
before: (nextValue: T, compareFn: ListComparisonFn<T> = compare) =>
this.addManyBefore(values, nextValue, compareFn),
byIndex: (position: number) => this.addManyByIndex(values, position),
head: () => this.addManyHead(values),
tail: () => this.addManyTail(values),
};
}
addAfter(value: T, previousValue: T, compareFn: ListComparisonFn<T> = compare): ListNode<T> {
const previous = this.find(node => compareFn(node.value, previousValue));
return previous ? this.attach(value, previous, previous.next) : this.addTail(value);
}
addBefore(value: T, nextValue: T, compareFn: ListComparisonFn<T> = compare): ListNode<T> {
const next = this.find(node => compareFn(node.value, nextValue));
return next ? this.attach(value, next.previous, next) : this.addHead(value);
}
addByIndex(value: T, position: number): ListNode<T> {
if (position < 0) position += this.size;
else if (position >= this.size) return this.addTail(value);
if (position <= 0) return this.addHead(value);
const next = this.get(position)!;
return this.attach(value, next.previous, next);
}
addHead(value: T): ListNode<T> {
const node = new ListNode(value);
node.next = this.first;
if (this.first) this.first.previous = node;
else this.last = node;
this.first = node;
this.size++;
return node;
}
addTail(value: T): ListNode<T> {
const node = new ListNode(value);
if (this.first) {
node.previous = this.last;
this.last!.next = node;
this.last = node;
} else {
this.first = node;
this.last = node;
}
this.size++;
return node;
}
addManyAfter(
values: T[],
previousValue: T,
compareFn: ListComparisonFn<T> = compare,
): ListNode<T>[] {
const previous = this.find(node => compareFn(node.value, previousValue));
return previous ? this.attachMany(values, previous, previous.next) : this.addManyTail(values);
}
addManyBefore(
values: T[],
nextValue: T,
compareFn: ListComparisonFn<T> = compare,
): ListNode<T>[] {
const next = this.find(node => compareFn(node.value, nextValue));
return next ? this.attachMany(values, next.previous, next) : this.addManyHead(values);
}
addManyByIndex(values: T[], position: number): ListNode<T>[] {
if (position < 0) position += this.size;
if (position <= 0) return this.addManyHead(values);
if (position >= this.size) return this.addManyTail(values);
const next = this.get(position)!;
return this.attachMany(values, next.previous, next);
}
addManyHead(values: T[]): ListNode<T>[] {
return values.reduceRight<ListNode<T>[]>((nodes, value) => {
nodes.unshift(this.addHead(value));
return nodes;
}, []);
}
addManyTail(values: T[]): ListNode<T>[] {
return values.map(value => this.addTail(value));
}
drop() {
return {
byIndex: (position: number) => this.dropByIndex(position),
byValue: (value: T, compareFn: ListComparisonFn<T> = compare) =>
this.dropByValue(value, compareFn),
byValueAll: (value: T, compareFn: ListComparisonFn<T> = compare) =>
this.dropByValueAll(value, compareFn),
head: () => this.dropHead(),
tail: () => this.dropTail(),
};
}
dropMany(count: number) {
return {
byIndex: (position: number) => this.dropManyByIndex(count, position),
head: () => this.dropManyHead(count),
tail: () => this.dropManyTail(count),
};
}
dropByIndex(position: number): ListNode<T> | undefined {
if (position < 0) position += this.size;
const current = this.get(position);
return current ? this.detach(current) : undefined;
}
dropByValue(value: T, compareFn: ListComparisonFn<T> = compare): ListNode<T> | undefined {
const position = this.findIndex(node => compareFn(node.value, value));
return position < 0 ? undefined : this.dropByIndex(position);
}
dropByValueAll(value: T, compareFn: ListComparisonFn<T> = compare): ListNode<T>[] {
const dropped: ListNode<T>[] = [];
for (let current = this.first, position = 0; current; position++, current = current.next) {
if (compareFn(current.value, value)) {
dropped.push(this.dropByIndex(position - dropped.length)!);
}
}
return dropped;
}
dropHead(): ListNode<T> | undefined {
const head = this.first;
if (head) {
this.first = head.next;
if (this.first) this.first.previous = undefined;
else this.last = undefined;
this.size--;
return head;
}
return undefined;
}
dropTail(): ListNode<T> | undefined {
const tail = this.last;
if (tail) {
this.last = tail.previous;
if (this.last) this.last.next = undefined;
else this.first = undefined;
this.size--;
return tail;
}
return undefined;
}
dropManyByIndex(count: number, position: number): ListNode<T>[] {
if (count <= 0) return [];
if (position < 0) position = Math.max(position + this.size, 0);
else if (position >= this.size) return [];
count = Math.min(count, this.size - position);
const dropped: ListNode<T>[] = [];
while (count--) {
const current = this.get(position);
dropped.push(this.detach(current!)!);
}
return dropped;
}
dropManyHead(count: Exclude<number, 0>): ListNode<T>[] {
if (count <= 0) return [];
count = Math.min(count, this.size);
const dropped: ListNode<T>[] = [];
while (count--) dropped.unshift(this.dropHead()!);
return dropped;
}
dropManyTail(count: Exclude<number, 0>): ListNode<T>[] {
if (count <= 0) return [];
count = Math.min(count, this.size);
const dropped: ListNode<T>[] = [];
while (count--) dropped.push(this.dropTail()!);
return dropped;
}
find(predicate: ListIteratorFn<T>): ListNode<T> | undefined {
for (let current = this.first, position = 0; current; position++, current = current.next) {
if (predicate(current, position, this)) return current;
}
return undefined;
}
findIndex(predicate: ListIteratorFn<T>): number {
for (let current = this.first, position = 0; current; position++, current = current.next) {
if (predicate(current, position, this)) return position;
}
return -1;
}
forEach<R = boolean>(callback: ListIteratorFn<T, R>) {
for (let node = this.first, position = 0; node; position++, node = node.next) {
callback(node, position, this);
}
}
get(position: number): ListNode<T> | undefined {
return this.find((_, index) => position === index);
}
indexOf(value: T, compareFn: ListComparisonFn<T> = compare): number {
return this.findIndex(node => compareFn(node.value, value));
}
toArray(): T[] {
const array = new Array(this.size);
this.forEach((node, index) => (array[index!] = node.value));
return array;
}
toNodeArray(): ListNode<T>[] {
const array = new Array(this.size);
this.forEach((node, index) => (array[index!] = node));
return array;
}
toString(mapperFn: ListMapperFn<T> = JSON.stringify): string {
return this.toArray()
.map(value => mapperFn(value))
.join(' <-> ');
}
*[Symbol.iterator]() {
for (let node = this.first, position = 0; node; position++, node = node.next) {
yield node.value;
}
}
}
export type ListMapperFn<T = any> = (value: T) => any;
export type ListComparisonFn<T = any> = (value1: T, value2: T) => boolean;
export type ListIteratorFn<T = any, R = boolean> = (
node: ListNode<T>,
index?: number,
list?: LinkedList,
) => R;
Loading…
Cancel
Save