Skip to content

Commit 9079d5d

Browse files
committed
Add ability to write all manifests to a directory with one command
1 parent 6540534 commit 9079d5d

File tree

4 files changed

+85
-8
lines changed

4 files changed

+85
-8
lines changed

src/AppInstallerCLICore/Commands/DscCommand.cpp

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,22 @@
1212

1313
namespace AppInstaller::CLI
1414
{
15+
namespace
16+
{
17+
Argument GetOutputFileArgument()
18+
{
19+
return { Execution::Args::Type::OutputFile, Resource::String::OutputFileArgumentDescription, ArgumentType::Standard };
20+
}
21+
}
22+
23+
DscCommand::DscCommand(std::string_view parent) :
24+
Command(StaticName(), parent, Settings::ExperimentalFeature::Feature::ConfigurationDSCv3)
25+
{
26+
}
27+
1528
std::vector<std::unique_ptr<Command>> DscCommand::GetCommands() const
1629
{
30+
// These should all derive from DscCommandBase
1731
return InitializeFromMoveOnly<std::vector<std::unique_ptr<Command>>>({
1832
std::make_unique<DscPackageResource>(FullName()),
1933
std::make_unique<DscSourceResource>(FullName()),
@@ -24,6 +38,16 @@ namespace AppInstaller::CLI
2438
});
2539
}
2640

41+
std::vector<Argument> DscCommand::GetArguments() const
42+
{
43+
std::vector<Argument> result;
44+
45+
result.emplace_back(Execution::Args::Type::DscResourceFunctionManifest, Resource::String::DscResourceFunctionDescriptionManifest, ArgumentType::Flag);
46+
result.emplace_back(GetOutputFileArgument());
47+
48+
return result;
49+
}
50+
2751
Resource::LocString DscCommand::ShortDescription() const
2852
{
2953
return { Resource::String::DscCommandShortDescription };
@@ -41,6 +65,34 @@ namespace AppInstaller::CLI
4165

4266
void DscCommand::ExecuteInternal(Execution::Context& context) const
4367
{
44-
OutputHelp(context.Reporter);
68+
if (context.Args.Contains(Execution::Args::Type::DscResourceFunctionManifest))
69+
{
70+
std::filesystem::path outputDirectory{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)) };
71+
std::filesystem::create_directories(outputDirectory);
72+
73+
std::string filePrefix = Utility::ToLower(DscCommandBase::ModuleName());
74+
75+
for (const auto& command : GetCommands())
76+
{
77+
DscCommandBase* commandBase = static_cast<DscCommandBase*>(command.get());
78+
79+
std::filesystem::path outputPath = outputDirectory;
80+
outputPath /= std::string{ filePrefix }.append(".").append(commandBase->Name()).append(".dsc.resource.json");
81+
commandBase->WriteManifest(context, outputPath);
82+
}
83+
}
84+
else
85+
{
86+
OutputHelp(context.Reporter);
87+
}
88+
}
89+
90+
void DscCommand::ValidateArgumentsInternal(Execution::Args& args) const
91+
{
92+
if (args.Contains(Execution::Args::Type::DscResourceFunctionManifest) &&
93+
!args.Contains(Execution::Args::Type::OutputFile))
94+
{
95+
throw CommandException(Resource::String::RequiredArgError(GetOutputFileArgument().Name()));
96+
}
4597
}
4698
}

src/AppInstallerCLICore/Commands/DscCommand.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,12 @@ namespace AppInstaller::CLI
88
{
99
struct DscCommand final : public Command
1010
{
11-
DscCommand(std::string_view parent) : Command(StaticName(), parent, Settings::ExperimentalFeature::Feature::ConfigurationDSCv3) {}
11+
DscCommand(std::string_view parent);
1212

1313
static constexpr std::string_view StaticName() { return "dscv3"sv; };
1414

1515
std::vector<std::unique_ptr<Command>> GetCommands() const override;
16+
std::vector<Argument> GetArguments() const override;
1617

1718
Resource::LocString ShortDescription() const override;
1819
Resource::LocString LongDescription() const override;
@@ -21,5 +22,6 @@ namespace AppInstaller::CLI
2122

2223
protected:
2324
void ExecuteInternal(Execution::Context& context) const override;
25+
void ValidateArgumentsInternal(Execution::Args& args) const override;
2426
};
2527
}

src/AppInstallerCLICore/Commands/DscCommandBase.cpp

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@ namespace AppInstaller::CLI
2222
{
2323
namespace
2424
{
25-
constexpr std::string_view s_WingetModuleName = "Microsoft.WinGet"sv;
26-
2725
std::string GetFunctionManifestString(DscFunctions function)
2826
{
2927
THROW_HR_IF(E_INVALIDARG, !WI_IsSingleFlagSet(function));
@@ -224,14 +222,23 @@ namespace AppInstaller::CLI
224222

225223
WINGET_DSC_FUNCTION_FOREACH(WINGET_DSC_FUNCTION_METHOD);
226224

227-
void DscCommandBase::ResourceFunctionManifest(Execution::Context& context) const
225+
std::string_view DscCommandBase::ModuleName()
226+
{
227+
#ifndef AICLI_DISABLE_TEST_HOOKS
228+
return "Microsoft.WinGet.Dev"sv;
229+
#else
230+
return "Microsoft.WinGet"sv;
231+
#endif
232+
}
233+
234+
void DscCommandBase::WriteManifest(Execution::Context& context, const std::filesystem::path& filePath) const
228235
{
229236
Json::Value json{ Json::ValueType::objectValue };
230237

231238
// TODO: Move to release schema when released (there should be an aka.ms link as well, but it wasn't active yet)
232239
//json["$schema"] = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/v3/bundled/resource/manifest.json";
233240
json["$schema"] = "https://raw.githubusercontent.com/PowerShell/DSC/main/schemas/2024/04/bundled/resource/manifest.json";
234-
json["type"] = std::string{ s_WingetModuleName } + '/' + ResourceType();
241+
json["type"] = std::string{ ModuleName() } + '/' + ResourceType();
235242
json["description"] = LongDescription().get();
236243
json["version"] = Runtime::GetClientVersion().get();
237244

@@ -253,9 +260,9 @@ namespace AppInstaller::CLI
253260
writerBuilder.settings_["indentation"] = " ";
254261
std::string jsonString = Json::writeString(writerBuilder, json);
255262

256-
if (context.Args.Contains(Execution::Args::Type::OutputFile))
263+
if (!filePath.empty())
257264
{
258-
std::ofstream stream{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)), std::ios::binary };
265+
std::ofstream stream{ filePath, std::ios::binary };
259266
stream.write(jsonString.c_str(), jsonString.length());
260267
}
261268
else
@@ -264,6 +271,16 @@ namespace AppInstaller::CLI
264271
}
265272
}
266273

274+
void DscCommandBase::ResourceFunctionManifest(Execution::Context& context) const
275+
{
276+
std::filesystem::path path;
277+
if (context.Args.Contains(Execution::Args::Type::OutputFile))
278+
{
279+
path = std::filesystem::path{ Utility::ConvertToUTF16(context.Args.GetArg(Execution::Args::Type::OutputFile)) };
280+
}
281+
WriteManifest(context, path);
282+
}
283+
267284
#undef WINGET_DSC_FUNCTION_METHOD
268285

269286
std::optional<Json::Value> DscCommandBase::GetJsonFromInput(Execution::Context& context, bool terminateContextOnError) const

src/AppInstallerCLICore/Commands/DscCommandBase.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,12 @@ namespace AppInstaller::CLI
7575

7676
Utility::LocIndView HelpLink() const override;
7777

78+
static std::string_view ModuleName();
79+
80+
// Writes the manifest for the command to the file path.
81+
// If the path is empty, writes the manifest to the output stream.
82+
void WriteManifest(Execution::Context& context, const std::filesystem::path& filePath) const;
83+
7884
protected:
7985
void ExecuteInternal(Execution::Context& context) const override;
8086

0 commit comments

Comments
 (0)