Skip to content

Commit 3a0126b

Browse files
committed
exec command
1 parent e759a85 commit 3a0126b

File tree

7 files changed

+172
-9
lines changed

7 files changed

+172
-9
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ pack
55
.vs
66
.idea
77
nupkg
8-
.config
8+
.config
9+
.df.ini

Deployf.Cli.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
<PackAsTool>true</PackAsTool>
99
<ToolCommandName>df</ToolCommandName>
1010
<PackageOutputPath>./nupkg</PackageOutputPath>
11+
12+
<NoWarn>NU1701</NoWarn>
1113
</PropertyGroup>
1214

1315
<ItemGroup>

ExecCommand.cs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
using CliFx;
2+
using CliFx.Attributes;
3+
using CliFx.Infrastructure;
4+
using System.Net;
5+
using System.Net.Http.Headers;
6+
7+
[Command("exec", Description = "exec command in the app container")]
8+
public class ExecCommand : ApplicationBaseCommand, ICommand
9+
{
10+
[CommandParameter(0)]
11+
public string Command { get; set; }
12+
13+
public async ValueTask ExecuteAsync(IConsole console)
14+
{
15+
var request = new HttpRequestMessage();
16+
request.Method = HttpMethod.Put;
17+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Token);
18+
request.RequestUri = new Uri(new Uri(ApiUrl), $"api/application/{AppId}/exec");
19+
var content = new MultipartFormDataContent();
20+
21+
foreach(var command in ParseCmd(Command))
22+
{
23+
content.Add(new StringContent(command), "command");
24+
}
25+
26+
if(console.IsInputRedirected)
27+
{
28+
content.Add(new StreamContent(console.Input.BaseStream), "file", "stdin");
29+
}
30+
31+
request.Content = content;
32+
33+
var response = await new HttpClient().SendAsync(request);
34+
35+
response.EnsureSuccessStatusCode();
36+
37+
await response.Content.ReadAsStream().CopyToAsync(console.Output.BaseStream);
38+
}
39+
40+
static IEnumerable<string> ParseCmd(string command)
41+
{
42+
if (command.Length == 0)
43+
{
44+
yield break;
45+
}
46+
47+
var inSubstring = false;
48+
var start = 0;
49+
var inEncaps = false;
50+
51+
for (int i = 0; i < command.Length; i++)
52+
{
53+
if (inEncaps)
54+
{
55+
inEncaps = false;
56+
continue;
57+
}
58+
59+
var ch = command[i];
60+
61+
if (inSubstring)
62+
{
63+
if (ch == '"' || ch == '\'')
64+
{
65+
inSubstring = false;
66+
yield return Trim(command[start..i]);
67+
start = i + 1;
68+
}
69+
continue;
70+
}
71+
72+
if (ch == ' ' || ch == '\t')
73+
{
74+
if (i == start || command[start] == ' ' || command[start] == '\t')
75+
{
76+
start = i + 1;
77+
}
78+
else
79+
{
80+
yield return Trim(command[start..i]);
81+
start = i + 1;
82+
}
83+
}
84+
else if (ch == '"' || ch == '\'')
85+
{
86+
inSubstring = true;
87+
if ((i - start) >= 1)
88+
{
89+
yield return Trim(command[start..i]);
90+
}
91+
start = i + 1;
92+
}
93+
else if (ch == '\\')
94+
{
95+
inEncaps = true;
96+
}
97+
}
98+
99+
if ((command.Length - 1) >= start && command.Last() != '"' && command.Last() != '\'')
100+
{
101+
yield return Trim(command.Substring(start));
102+
}
103+
else if (start == 0 && command.Length > 0)
104+
{
105+
yield return Trim(command.Substring(start));
106+
}
107+
else if (start == 0 && command.Length == 1)
108+
{
109+
yield return command;
110+
}
111+
112+
string Trim(string input)
113+
{
114+
return input.Replace("\\'", "'").Replace("\\\"", "\"").Replace("\\\\", "\\");
115+
}
116+
}
117+
}

InitCommand.cs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class InitCommand : ICommand
1111
[CommandOption("api-url", Description = "set the url to api")]
1212
public string ApiUrl { get; set; }
1313

14-
public async ValueTask ExecuteAsync(IConsole console)
14+
public ValueTask ExecuteAsync(IConsole console)
1515
{
1616
var home = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
1717
var dfPath = Path.Combine(home, ".df");
@@ -31,5 +31,7 @@ public async ValueTask ExecuteAsync(IConsole console)
3131
File.WriteAllText(confPath, config);
3232

3333
console.Output.WriteLine($"config has been saved to {confPath}");
34+
35+
return ValueTask.CompletedTask;
3436
}
3537
}

Properties/launchSettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"profiles": {
33
"Deployf.Cli": {
44
"commandName": "Project",
5-
"commandLineArgs": "upload /app/test.txt --app-id 7 --file ../../../swagger-codegen.ps1"
5+
"commandLineArgs": "exec pwd --app-id 7"
66
}
77
}
88
}

SetAppIdCommand.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using CliFx;
2+
using CliFx.Attributes;
3+
using CliFx.Infrastructure;
4+
using IO.Swagger.Api;
5+
6+
[Command("set-app-id", Description = "set context to use passed app id")]
7+
public class SetAppIdCommand : ApplicationBaseCommand, ICommand
8+
{
9+
[CommandParameter(0)]
10+
public int appId { get; set; }
11+
12+
public async ValueTask ExecuteAsync(IConsole console)
13+
{
14+
var content = File.Exists(".df.ini") ? await File.ReadAllTextAsync(".df.ini") : "";
15+
var data = new Dictionary<string, string>();
16+
var lines = content.Split('\n', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
17+
foreach (var line in lines)
18+
{
19+
var items = line.Split('=', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
20+
if (items.Length == 2)
21+
{
22+
data[items[0]] = items[1];
23+
}
24+
}
25+
26+
data["APP_ID"] = appId.ToString();
27+
28+
var resultContent = string.Join("\n", data.Select(x => $"{x.Key}={x.Value}"));
29+
await File.WriteAllTextAsync(".df.ini", resultContent);
30+
console.Output.WriteLine("OK");
31+
}
32+
}

UploadFileCommand.cs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
using CliFx;
22
using CliFx.Attributes;
33
using CliFx.Infrastructure;
4-
using IO.Swagger.Api;
4+
using System.Net.Http.Headers;
55

66
[Command("upload", Description = "uplaoad file to the container")]
77
public class UploadFileCommand : ApplicationBaseCommand, ICommand
88
{
9-
109
[CommandParameter(0)]
1110
public string ContainerPath { get; set; }
1211

@@ -15,12 +14,22 @@ public class UploadFileCommand : ApplicationBaseCommand, ICommand
1514

1615
public async ValueTask ExecuteAsync(IConsole console)
1716
{
18-
var api = GetApi<ApplicationApi>();
19-
2017
using Stream file = console.IsInputRedirected ? console.Input.BaseStream : File.OpenRead(SourceFile);
2118

22-
var response = api.Exec(AppId, new List<string> { "tee", ContainerPath }, file);
19+
var request = new HttpRequestMessage();
20+
request.Method = HttpMethod.Put;
21+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", Token);
22+
request.RequestUri = new Uri(new Uri(ApiUrl), $"api/application/{AppId}/exec");
23+
var content = new MultipartFormDataContent();
24+
content.Add(new StringContent("tee"), "command");
25+
content.Add(new StringContent(ContainerPath), "command");
26+
content.Add(new StreamContent(file), "file", "stdin");
27+
request.Content = content;
28+
29+
var response = await new HttpClient().SendAsync(request);
30+
31+
response.EnsureSuccessStatusCode();
2332

24-
console.Output.BaseStream.Write(response);
33+
await response.Content.ReadAsStream().CopyToAsync(console.Output.BaseStream);
2534
}
2635
}

0 commit comments

Comments
 (0)