Skip to content

Commit

Permalink
Merge #3876 Repository management fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
HebaruSan committed Aug 8, 2023
2 parents 2a5a94c + 8382f6b commit 1d88407
Show file tree
Hide file tree
Showing 11 changed files with 267 additions and 106 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file.
- [Multiple] Fix deletion of unmanaged files (#3865 by: HebaruSan; reviewed: techman83)
- [Build] Add missing dependency to .deb package (#3872 by: HebaruSan; reviewed: erkinalp)
- [Core] Add missing resource string for upgrading (#3873 by: HebaruSan; reviewed: techman83)
- [Multiple] Repository management fixes (#3876 by: HebaruSan; reviewed: techman83)

### Internal

Expand Down
147 changes: 118 additions & 29 deletions Cmdline/Action/Repo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;

using Newtonsoft.Json;
using CommandLine;
using CommandLine.Text;
Expand All @@ -20,6 +21,9 @@ public class RepoSubOptions : VerbCommandOptions
[VerbOption("add", HelpText = "Add a repository")]
public RepoAddOptions AddOptions { get; set; }

[VerbOption("priority", HelpText = "Set repository priority")]
public RepoPriorityOptions PriorityOptions { get; set; }

[VerbOption("forget", HelpText = "Forget a repository")]
public RepoForgetOptions ForgetOptions { get; set; }

Expand All @@ -44,6 +48,7 @@ public string GetUsage(string verb)
{
// First the commands with two arguments
case "add":
case "priority":
ht.AddPreOptionsLine($"{Properties.Resources.Usage}: ckan repo {verb} [{Properties.Resources.Options}] name url");
break;

Expand Down Expand Up @@ -75,6 +80,12 @@ public class RepoAddOptions : InstanceSpecificOptions
[ValueOption(1)] public string uri { get; set; }
}

public class RepoPriorityOptions : InstanceSpecificOptions
{
[ValueOption(0)] public string name { get; set; }
[ValueOption(1)] public int priority { get; set; }
}

public class RepoDefaultOptions : InstanceSpecificOptions
{
[ValueOption(0)] public string uri { get; set; }
Expand Down Expand Up @@ -138,6 +149,10 @@ public int RunSubCommand(GameInstanceManager manager, CommonOptions opts, SubCom
exitCode = AddRepository((RepoAddOptions)suboptions);
break;
case "priority":
exitCode = SetRepositoryPriority((RepoPriorityOptions)suboptions);
break;
case "remove":
case "forget":
exitCode = ForgetRepository((RepoForgetOptions)suboptions);
Expand Down Expand Up @@ -199,21 +214,39 @@ private int AvailableRepositories()

private int ListRepositories()
{
var manager = RegistryManager.Instance(MainClass.GetGameInstance(Manager));
User.RaiseMessage(Properties.Resources.RepoListHeader);
SortedDictionary<string, Repository> repositories = manager.registry.Repositories;

int maxNameLen = 0;
foreach (Repository repository in repositories.Values)
var repositories = RegistryManager.Instance(MainClass.GetGameInstance(Manager)).registry.Repositories;

string priorityHeader = Properties.Resources.RepoListPriorityHeader;
string nameHeader = Properties.Resources.RepoListNameHeader;
string urlHeader = Properties.Resources.RepoListURLHeader;

var priorityWidth = Enumerable.Repeat(priorityHeader, 1)
.Concat(repositories.Values.Select(r => $"{r.priority}"))
.Max(str => str.Length);
var nameWidth = Enumerable.Repeat(nameHeader, 1)
.Concat(repositories.Values.Select(r => r.name))
.Max(str => str.Length);
var urlWidth = Enumerable.Repeat(urlHeader, 1)
.Concat(repositories.Values.Select(r => $"{r.uri}"))
.Max(str => str.Length);

const string columnFormat = "{0} {1} {2}";

User.RaiseMessage(columnFormat,
priorityHeader.PadRight(priorityWidth),
nameHeader.PadRight(nameWidth),
urlHeader.PadRight(urlWidth));
User.RaiseMessage(columnFormat,
new string('-', priorityWidth),
new string('-', nameWidth),
new string('-', urlWidth));
foreach (Repository repository in repositories.Values.OrderBy(r => r.priority))
{
maxNameLen = Math.Max(maxNameLen, repository.name.Length);
User.RaiseMessage(columnFormat,
repository.priority.ToString().PadRight(priorityWidth),
repository.name.PadRight(nameWidth),
repository.uri);
}

foreach (Repository repository in repositories.Values)
{
User.RaiseMessage(" {0}: {1}: {2}", repository.name.PadRight(maxNameLen), repository.priority, repository.uri);
}

return Exit.OK;
}

Expand Down Expand Up @@ -259,22 +292,78 @@ private int AddRepository(RepoAddOptions options)
}

log.DebugFormat("About to add repository '{0}' - '{1}'", options.name, options.uri);
SortedDictionary<string, Repository> repositories = manager.registry.Repositories;
var repositories = manager.registry.Repositories;

if (repositories.ContainsKey(options.name))
{
User.RaiseMessage(Properties.Resources.RepoAddDuplicate, options.name);
return Exit.BADOPT;
}
if (repositories.Values.Any(r => r.uri.ToString() == options.uri))
{
User.RaiseMessage(Properties.Resources.RepoAddDuplicateURL, options.uri);
return Exit.BADOPT;
}

repositories.Add(options.name, new Repository(options.name, options.uri));
repositories.Add(options.name,
new Repository(options.name, options.uri, manager.registry.Repositories.Count));

User.RaiseMessage(Properties.Resources.RepoAdded, options.name, options.uri);
manager.Save();

return Exit.OK;
}

private int SetRepositoryPriority(RepoPriorityOptions options)
{
if (options.name == null)
{
User.RaiseMessage("priority <name> <priority> - {0}", Properties.Resources.ArgumentMissing);
return Exit.BADOPT;
}
var manager = RegistryManager.Instance(MainClass.GetGameInstance(Manager));
if (options.priority < 0 || options.priority > manager.registry.Repositories.Count)
{
User.RaiseMessage(Properties.Resources.RepoPriorityInvalid,
options.priority, manager.registry.Repositories.Count - 1);
return Exit.BADOPT;
}

if (manager.registry.Repositories.TryGetValue(options.name, out Repository repo))
{
if (options.priority != repo.priority)
{
var sortedRepos = manager.registry.Repositories.Values
.OrderBy(r => r.priority)
.ToList();
// Shift other repos up or down by 1 to make room in the list
if (options.priority < repo.priority)
{
for (int i = options.priority; i < repo.priority; ++i)
{
sortedRepos[i].priority = i + 1;
}
}
else
{
for (int i = repo.priority + 1; i <= options.priority; ++i)
{
sortedRepos[i].priority = i - 1;
}
}
// Move chosen repo into new spot and save
repo.priority = options.priority;
manager.Save();
}
return ListRepositories();
}
else
{
User.RaiseMessage(Properties.Resources.RepoPriorityNotFound, options.name);
return Exit.BADOPT;
}
}

private int ForgetRepository(RepoForgetOptions options)
{
if (options.name == null)
Expand All @@ -284,10 +373,9 @@ private int ForgetRepository(RepoForgetOptions options)
}

RegistryManager manager = RegistryManager.Instance(MainClass.GetGameInstance(Manager));
var registry = manager.registry;
log.DebugFormat("About to forget repository '{0}'", options.name);

var repos = registry.Repositories;
var repos = manager.registry.Repositories;

string name = options.name;
if (!repos.ContainsKey(options.name))
Expand All @@ -301,7 +389,12 @@ private int ForgetRepository(RepoForgetOptions options)
User.RaiseMessage(Properties.Resources.RepoForgetRemoving, name);
}

registry.Repositories.Remove(name);
repos.Remove(name);
var remaining = repos.Values.OrderBy(r => r.priority).ToArray();
for (int i = 0; i < remaining.Length; ++i)
{
remaining[i].priority = i;
}
User.RaiseMessage(Properties.Resources.RepoForgetRemoved, options.name);
manager.Save();

Expand All @@ -310,26 +403,22 @@ private int ForgetRepository(RepoForgetOptions options)

private int DefaultRepository(RepoDefaultOptions options)
{
RegistryManager manager = RegistryManager.Instance(MainClass.GetGameInstance(Manager));

if (options.uri == null)
{
User.RaiseMessage("default <uri> - {0}", Properties.Resources.ArgumentMissing);
return Exit.BADOPT;
}
var inst = MainClass.GetGameInstance(Manager);
var uri = options.uri ?? inst.game.DefaultRepositoryURL.ToString();

log.DebugFormat("About to add repository '{0}' - '{1}'", Repository.default_ckan_repo_name, options.uri);
SortedDictionary<string, Repository> repositories = manager.registry.Repositories;
log.DebugFormat("About to add repository '{0}' - '{1}'", Repository.default_ckan_repo_name, uri);
RegistryManager manager = RegistryManager.Instance(inst);
var repositories = manager.registry.Repositories;

if (repositories.ContainsKey(Repository.default_ckan_repo_name))
{
repositories.Remove(Repository.default_ckan_repo_name);
}

repositories.Add(Repository.default_ckan_repo_name, new Repository(
Repository.default_ckan_repo_name, options.uri));
Repository.default_ckan_repo_name, uri, repositories.Count));

User.RaiseMessage(Properties.Resources.RepoSet, Repository.default_ckan_repo_name, options.uri);
User.RaiseMessage(Properties.Resources.RepoSet, Repository.default_ckan_repo_name, uri);
manager.Save();

return Exit.OK;
Expand Down
2 changes: 1 addition & 1 deletion Cmdline/ConsoleUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ public void RaiseError(string message, params object[] args)
/// <param name="percent">Progress in percent</param>
public void RaiseProgress(string message, int percent)
{
if (Regex.IsMatch(message, "download", RegexOptions.IgnoreCase))
if (Regex.IsMatch(message, Properties.Resources.UserProgressDownloadSubstring, RegexOptions.IgnoreCase))
{
// In headless mode, only print a new message if the percent has changed,
// to reduce clutter in Jenkins for large downloads
Expand Down
22 changes: 20 additions & 2 deletions Cmdline/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 7 additions & 1 deletion Cmdline/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ Update recommended!</value></data>
<data name="UserSelectionNotNumber" xml:space="preserve"><value>The input is not a number</value></data>
<data name="UserSelectionTooLarge" xml:space="preserve"><value>The number in the input is too large</value></data>
<data name="UserSelectionTooSmall" xml:space="preserve"><value>The number in the input is too small</value></data>
<data name="UserProgressDownloadSubstring" xml:space="preserve"><value>download</value><comment>Progress update messages containing this will display a percentage and overwrite the same line on the screen</comment></data>
<data name="AuthTokenHostHeader" xml:space="preserve"><value>Host</value></data>
<data name="AuthTokenTokenHeader" xml:space="preserve"><value>Token</value></data>
<data name="AuthTokenHelpSummary" xml:space="preserve"><value>Manage authentication tokens</value></data>
Expand Down Expand Up @@ -293,10 +294,15 @@ Try `ckan list` for a list of installed mods.</value></data>
<data name="RepoUnknownCommand" xml:space="preserve"><value>Unknown command: repo {0}</value></data>
<data name="RepoAvailableHeader" xml:space="preserve"><value>Listing all (canonical) available CKAN repositories:</value></data>
<data name="RepoAvailableFailed" xml:space="preserve"><value>Couldn't fetch CKAN repositories master list from {0}</value></data>
<data name="RepoListHeader" xml:space="preserve"><value>Listing all known repositories:</value></data>
<data name="RepoListPriorityHeader" xml:space="preserve"><value>Priority</value></data>
<data name="RepoListNameHeader" xml:space="preserve"><value>Name</value></data>
<data name="RepoListURLHeader" xml:space="preserve"><value>URL</value></data>
<data name="RepoAddNotFound" xml:space="preserve"><value>Name {0} not found in master list, please provide name and uri</value></data>
<data name="RepoAddDuplicate" xml:space="preserve"><value>Repository with name "{0}" already exists, aborting</value></data>
<data name="RepoAddDuplicateURL" xml:space="preserve"><value>Repository with URL "{0}" already exists, aborting</value></data>
<data name="RepoAdded" xml:space="preserve"><value>Added repository '{0}' - '{1}'</value></data>
<data name="RepoPriorityNotFound" xml:space="preserve"><value>Couldn't find repository with name "{0}", aborting</value></data>
<data name="RepoPriorityInvalid" xml:space="preserve"><value>Invalid priority: {0}, allowed values are 0 to {1}</value></data>
<data name="RepoForgetNotFound" xml:space="preserve"><value>Couldn't find repository with name "{0}", aborting</value></data>
<data name="RepoForgetRemoving" xml:space="preserve"><value>Removing insensitive match "{0}"</value></data>
<data name="RepoForgetRemoved" xml:space="preserve"><value>Successfully removed "{0}"</value></data>
Expand Down
4 changes: 3 additions & 1 deletion Core/Net/Repo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public static RepoUpdateResult UpdateAllRepositories(RegistryManager registry_ma
{
var repos = registry_manager.registry.Repositories.Values
.DistinctBy(r => r.uri)
// Higher priority repo overwrites lower priority (SortedDictionary just sorts by name)
.OrderByDescending(r => r.priority)
.ToArray();

// Get latest copy of the game versions data (remote build map)
Expand Down Expand Up @@ -203,7 +205,7 @@ private static List<CkanModule> ModulesFromZip(Repository repo, string path, IUs
List<CkanModule> modules = new List<CkanModule>();
using (var zipfile = new ZipFile(path))
{
user.RaiseMessage("Loading modules from {0} repository...", repo.name);
user.RaiseMessage(Properties.Resources.NetRepoLoadingModulesFromRepo, repo.name);
int index = 0;
int prevPercent = 0;
foreach (ZipEntry entry in zipfile)
Expand Down
Loading

0 comments on commit 1d88407

Please sign in to comment.