Skip to content

Commit

Permalink
Merge #2671 Support replaced_by property
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Feb 25, 2019
2 parents d42a88d + 192b47b commit a971475
Show file tree
Hide file tree
Showing 44 changed files with 1,094 additions and 277 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ All notable changes to this project will be documented in this file.
- [Build] Use Core.Utilities.CopyDirectory in tests (#2670 by: DasSkelett; reviewed: HebaruSan)
- [Core] Avoid redundant metadata downloads (#2682 by: HebaruSan, reviewed: DasSkelett, politas)
- [Netkan] Releases option for Netkan (#2681 by: HebaruSan, reviewed: politas)
- [Multiple] Support replaced_by property (#2671 by: politas, HebaruSan; reviewed: DasSkelett, politas)

### Bugfixes

Expand Down
19 changes: 19 additions & 0 deletions CKAN.schema
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,25 @@
"items" : { "type" : "string" },
"uniqueItems" : true
},
"replaced_by" : {
"description" : "Optional pointer to mod that should be selected instead and treated as an update to this mod",
"type" : "object",
"properties" : {
"name" : {
"description" : "Identifier of the mod",
"$ref" : "#/definitions/identifier"
},
"version" : {
"description" : "Optional version",
"$ref" : "#/definitions/version"
},
"min_version" : {
"description" : "Optional minimum version",
"$ref" : "#/definitions/version"
}
},
"required" : [ "name" ]
},
"resources" : {
"description" : "Additional resources",
"type" : "object",
Expand Down
18 changes: 1 addition & 17 deletions Cmdline/Action/Install.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
// Parse the JSON file.
try
{
CkanModule m = LoadCkanFromFile(ksp, filename);
CkanModule m = MainClass.LoadCkanFromFile(ksp, filename);
options.modules.Add($"{m.identifier}={m.version}");
}
catch (Kraken kraken)
Expand Down Expand Up @@ -284,21 +284,5 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)

return Exit.OK;
}

internal static CkanModule LoadCkanFromFile(CKAN.KSP current_instance, string ckan_file)
{
CkanModule module = CkanModule.FromFile(ckan_file);

// We'll need to make some registry changes to do this.
RegistryManager registry_manager = RegistryManager.Instance(current_instance);

// Remove this version of the module in the registry, if it exists.
registry_manager.registry.RemoveAvailable(module);

// Sneakily add our version in...
registry_manager.registry.AddAvailable(module);

return module;
}
}
}
38 changes: 32 additions & 6 deletions Cmdline/Action/List.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
foreach (KeyValuePair<string, ModuleVersion> mod in installed)
{
ModuleVersion current_version = mod.Value;

string modInfo = string.Format("{0} {1}", mod.Key, mod.Value);
string bullet = "*";

if (current_version is ProvidesModuleVersion)
Expand All @@ -62,26 +62,52 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
else if (current_version is UnmanagedModuleVersion)
{
// Autodetected dll
bullet = "-";
bullet = "A";
}
else
{
try
{
// Check if upgrades are available, and show appropriately.
log.DebugFormat("Check if upgrades are available for {0}", mod.Key);
CkanModule latest = registry.LatestAvailable(mod.Key, ksp.VersionCriteria());

log.InfoFormat("Latest {0} is {1}", mod.Key, latest);
CkanModule current = registry.GetInstalledVersion(mod.Key);

if (latest == null)
{
// Not compatible!
log.InfoFormat("Latest {0} is not compatible", mod.Key);
bullet = "X";
if ( current == null ) log.DebugFormat( " {0} installed version not found in registry", mod.Key);

//Check if mod is replaceable
if ( current.replaced_by != null )
{
ModuleReplacement replacement = registry.GetReplacement(mod.Key, ksp.VersionCriteria());
if ( replacement != null )
{
//Replaceable!
bullet = ">";
modInfo = string.Format("{0} > {1} {2}", modInfo, replacement.ReplaceWith.name, replacement.ReplaceWith.version);
}
}
}
else if (latest.version.IsEqualTo(current_version))
{
// Up to date
log.InfoFormat("Latest {0} is {1}", mod.Key, latest.version);
bullet = "-";
//Check if mod is replaceable
if ( current.replaced_by != null )
{
ModuleReplacement replacement = registry.GetReplacement(latest.identifier, ksp.VersionCriteria());
if ( replacement != null )
{
//Replaceable!
bullet = ">";
modInfo = string.Format("{0} > {1} {2}", modInfo, replacement.ReplaceWith.name, replacement.ReplaceWith.version);
}
}
}
else if (latest.version.IsGreaterThan(mod.Value))
{
Expand All @@ -96,7 +122,7 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
}
}

user.RaiseMessage("{0} {1} {2}", bullet, mod.Key, mod.Value);
user.RaiseMessage("{0} {1}", bullet, modInfo);
}
}
else
Expand All @@ -108,7 +134,7 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)

if (!(options.porcelain) && exportFileType == null)
{
user.RaiseMessage("\r\nLegend: -: Up to date. X: Incompatible. ^: Upgradable. ?: Unknown. *: Broken. ");
user.RaiseMessage("\r\nLegend: -: Up to date. X: Incompatible. ^: Upgradable. >: Replaceable\r\n A: Autodetected. ?: Unknown. *: Broken. ");
// Broken mods are in a state that CKAN doesn't understand, and therefore can't handle automatically
}

Expand Down
175 changes: 175 additions & 0 deletions Cmdline/Action/Replace.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using log4net;
using CKAN.Versioning;

namespace CKAN.CmdLine
{
public class Replace : ICommand
{
private static readonly ILog log = LogManager.GetLogger(typeof(Replace));

public IUser User { get; set; }

public Replace(CKAN.KSPManager mgr, IUser user)
{
manager = mgr;
User = user;
}

private KSPManager manager;

public int RunCommand(CKAN.KSP ksp, object raw_options)
{
ReplaceOptions options = (ReplaceOptions) raw_options;

if (options.ckan_file != null)
{
options.modules.Add(MainClass.LoadCkanFromFile(ksp, options.ckan_file).identifier);
}

if (options.modules.Count == 0 && ! options.replace_all)
{
// What? No mods specified?
User.RaiseMessage("Usage: ckan replace Mod [Mod2, ...]");
User.RaiseMessage(" or ckan replace --all");
return Exit.BADOPT;
}

// Prepare options. Can these all be done in the new() somehow?
var replace_ops = new RelationshipResolverOptions
{
with_all_suggests = options.with_all_suggests,
with_suggests = options.with_suggests,
with_recommends = !options.no_recommends,
allow_incompatible = options.allow_incompatible
};

var registry = RegistryManager.Instance(ksp).registry;
var to_replace = new List<ModuleReplacement>();

if (options.replace_all)
{
log.Debug("Running Replace all");
var installed = new Dictionary<string, ModuleVersion>(registry.Installed());

foreach (KeyValuePair<string, ModuleVersion> mod in installed)
{
ModuleVersion current_version = mod.Value;

if ((current_version is ProvidesModuleVersion) || (current_version is UnmanagedModuleVersion))
{
continue;
}
else
{
try
{
log.DebugFormat("Testing {0} {1} for possible replacement", mod.Key, mod.Value);
// Check if replacement is available

ModuleReplacement replacement = registry.GetReplacement(mod.Key, ksp.VersionCriteria());
if (replacement != null)
{
// Replaceable
log.InfoFormat("Replacement {0} {1} found for {2} {3}",
replacement.ReplaceWith.identifier, replacement.ReplaceWith.version,
replacement.ToReplace.identifier, replacement.ToReplace.version);
to_replace.Add(replacement);
}
}
catch (ModuleNotFoundKraken)
{
log.InfoFormat("{0} is installed, but it or its replacement is not in the registry",
mod.Key);
}
}
}
}
else
{
foreach (string mod in options.modules)
{
try
{
log.DebugFormat("Checking that {0} is installed", mod);
CkanModule modToReplace = registry.GetInstalledVersion(mod);
if (modToReplace != null)
{
log.DebugFormat("Testing {0} {1} for possible replacement", modToReplace.identifier, modToReplace.version);
try
{
// Check if replacement is available
ModuleReplacement replacement = registry.GetReplacement(modToReplace.identifier, ksp.VersionCriteria());
if (replacement != null)
{
// Replaceable
log.InfoFormat("Replacement {0} {1} found for {2} {3}",
replacement.ReplaceWith.identifier, replacement.ReplaceWith.version,
replacement.ToReplace.identifier, replacement.ToReplace.version);
to_replace.Add(replacement);
}
if (modToReplace.replaced_by != null)
{
log.InfoFormat("Attempt to replace {0} failed, replacement {1} is not compatible",
mod, modToReplace.replaced_by.name);
}
else
{
log.InfoFormat("Mod {0} has no replacement defined for the current version {1}",
modToReplace.identifier, modToReplace.version);
}
}
catch (ModuleNotFoundKraken)
{
log.InfoFormat("{0} is installed, but its replacement {1} is not in the registry",
mod, modToReplace.replaced_by.name);
}
}
}
catch (ModuleNotFoundKraken kraken)
{
User.RaiseMessage("Module {0} not found", kraken.module);
}
}
}
if (to_replace.Count() != 0)
{
User.RaiseMessage("\r\nReplacing modules...\r\n");
foreach (ModuleReplacement r in to_replace)
{
User.RaiseMessage("Replacement {0} {1} found for {2} {3}",
r.ReplaceWith.identifier, r.ReplaceWith.version,
r.ToReplace.identifier, r.ToReplace.version);
}

bool ok = User.RaiseYesNoDialog("\r\nContinue?");

if (!ok)
{
User.RaiseMessage("Replacements canceled at user request.");
return Exit.ERROR;
}

// TODO: These instances all need to go.
try
{
ModuleInstaller.GetInstance(ksp, manager.Cache, User).Replace(to_replace, replace_ops, new NetAsyncModulesDownloader(User));
User.RaiseMessage("\r\nDone!\r\n");
}
catch (DependencyNotSatisfiedKraken ex)
{
User.RaiseMessage("Dependencies not satisfied for replacement, {0} requires {1} {2} but it is not listed in the index, or not available for your version of KSP.", ex.parent, ex.module, ex.version);
}
}
else
{
User.RaiseMessage("No replacements found.");
return Exit.OK;
}

return Exit.OK;
}
}
}
20 changes: 2 additions & 18 deletions Cmdline/Action/Upgrade.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)
UpgradeOptions options = (UpgradeOptions) raw_options;

if (options.ckan_file != null)
{
options.modules.Add(LoadCkanFromFile(ksp, options.ckan_file).identifier);
{
options.modules.Add(MainClass.LoadCkanFromFile(ksp, options.ckan_file).identifier);
}

if (options.modules.Count == 0 && ! options.upgrade_all)
Expand Down Expand Up @@ -152,21 +152,5 @@ public int RunCommand(CKAN.KSP ksp, object raw_options)

return Exit.OK;
}

internal static CkanModule LoadCkanFromFile(CKAN.KSP current_instance, string ckan_file)
{
CkanModule module = CkanModule.FromFile(ckan_file);

// We'll need to make some registry changes to do this.
RegistryManager registry_manager = RegistryManager.Instance(current_instance);

// Remove this version of the module in the registry, if it exists.
registry_manager.registry.RemoveAvailable(module);

// Sneakily add our version in...
registry_manager.registry.AddAvailable(module);

return module;
}
}
}
9 changes: 5 additions & 4 deletions Cmdline/CKAN-cmdline.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@
<Reference Include="CommandLine, Version=1.9.71.2, Culture=neutral, PublicKeyToken=de6f01bd326f8c32, processorArchitecture=MSIL">
<HintPath>..\_build\lib\nuget\CommandLineParser.1.9.71\lib\net45\CommandLine.dll</HintPath>
</Reference>
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a, processorArchitecture=MSIL">
<Reference Include="System" />
<Reference Include="System.Transactions" />
<Reference Include="log4net, Version=2.0.8.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a">
<HintPath>..\_build\lib\nuget\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
<HintPath>..\_build\lib\nuget\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Transactions" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\_build\meta\GlobalAssemblyVersionInfo.cs">
Expand All @@ -69,6 +69,7 @@
<Compile Include="Action\Remove.cs" />
<Compile Include="Action\Prompt.cs" />
<Compile Include="Action\Repair.cs" />
<Compile Include="Action\Replace.cs" />
<Compile Include="Action\Repo.cs" />
<Compile Include="Action\Search.cs" />
<Compile Include="Action\Show.cs" />
Expand Down
Loading

0 comments on commit a971475

Please sign in to comment.