Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a simple module registry #17

Merged
merged 1 commit into from
Sep 24, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CKAN/CKAN/CKAN.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@
<Compile Include="Module.cs" />
<Compile Include="ModuleDict.cs" />
<Compile Include="KSP.cs" />
<Compile Include="InstalledModule.cs" />
<Compile Include="RegistryManager.cs" />
<Compile Include="Registry.cs" />
<Compile Include="ModuleInstaller.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
</Project>
</Project>
24 changes: 24 additions & 0 deletions CKAN/CKAN/InstalledModule.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using System;

namespace CKAN
{
public class InstalledModuleFile
{
public string name;
public string sha1_sum;
}

public class InstalledModule
{
public InstalledModuleFile[] installed_files;
public Module source_module;
public DateTime install_time;

public InstalledModule (InstalledModuleFile[] installed_files, Module source_module, DateTime install_time)
{
this.installed_files = installed_files;
this.source_module = source_module;
this.install_time = install_time;
}
}
}
205 changes: 25 additions & 180 deletions CKAN/CKAN/Module.cs
Original file line number Diff line number Diff line change
@@ -1,15 +1,6 @@
using System;
using System.IO;
using System.Net;
using System.Linq;

using Newtonsoft.Json;

using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.Zip;

using System.Text.RegularExpressions;

/// <summary>
/// Describes a CKAN module (ie, what's in the CKAN.schema file).
///
Expand All @@ -35,226 +26,80 @@ namespace CKAN {
public class Module {

[JsonProperty("name", Required = Required.Always)]
public string _name;
public string name;

[JsonProperty("identifier", Required = Required.Always)]
public string _identifier; // TODO: Strong type
public string identifier; // TODO: Strong type

// TODO: Change spec: abstract -> description
[JsonProperty("abstract", Required = Required.Always)]
public string _abstract;
public string @abstract;

[JsonProperty("comment")]
public string _comment;
public string comment;

[JsonProperty("author")]
public string[] _author;
public string[] author;

[JsonProperty("download", Required = Required.Always)]
public Uri _download;
public Uri download;

[JsonProperty("license", Required= Required.Always)]
public dynamic _license; // TODO: Strong type
public dynamic license; // TODO: Strong type

[JsonProperty("version", Required = Required.Always)]
public string _version; // TODO: Strong type
public string version; // TODO: Strong type

[JsonProperty("release_status")]
public string _release_status; // TODO: Strong type
public string release_status; // TODO: Strong type

[JsonProperty("min_ksp")]
public string _min_ksp; // TODO: Type
public string min_ksp; // TODO: Type

[JsonProperty("max_ksp")]
public string _max_ksp; // TODO: Type
public string max_ksp; // TODO: Type

[JsonProperty("requires")]
public dynamic[] _requires;
public dynamic[] requires;

[JsonProperty("recommends")]
public dynamic[] _recommends;
public dynamic[] recommends;

[JsonProperty("conflicts")]
public dynamic[] _conflicts;
public dynamic[] conflicts;

[JsonProperty("resourcs")]
public dynamic[] _resources;
public dynamic[] resources;

[JsonProperty("install", Required = Required.Always)]
public dynamic[] _install;
public dynamic[] install;

[JsonProperty("bundles")]
public dynamic[] _bundles;

// Private record of which file we came from.
string origCkanFile;
public dynamic[] bundles;

/// <summary> Generates a CKAN.Meta object given a filename</summary>
public static Module from_file(string filename) {
string json = System.IO.File.ReadAllText (filename);

Module built = Module.from_string (json);

// Attach which file this came from.
built.origCkanFile = filename;

return built;
return Module.from_string (json);
}

/// <summary> Generates a CKAN.META object from a string </summary>
public static Module from_string(string json) {
return JsonConvert.DeserializeObject<Module> (json);
}

/// <summary>
/// Download the given mod. Returns the filename it was saved to.
///
/// If no filename is provided, the standard_name() will be used.
///
/// </summary>
/// <param name="filename">Filename.</param>
public string download(string filename = null) {

// Generate a temporary file if none is provided.
if (filename == null) {
filename = standard_name();
}

Console.WriteLine (" * Downloading " + filename + "...");

WebClient agent = new WebClient ();
agent.DownloadFile (_download, filename);

return filename;
}

/// <summary>
/// Returns a standardised name for this module, in the form
/// "identifier-version.zip". For example, `RealSolarSystem-7.3.zip`
/// </summary>
public string standard_name() {
return _identifier + "-" + _version + ".zip";
}

/// <summary>
/// Install our mod from the filename supplied.
/// If no file is supplied, we will fetch() it first.
/// </summary>

public void install(string filename = null) {

Console.WriteLine (_identifier + ":\n");

// Fetch our file if we don't already have it.
if (filename == null) {
filename = download ();
}

// Open our zip file for processing
ZipFile zipfile = new ZipFile (File.OpenRead (filename));

// Walk through our install instructions.
foreach (dynamic stanza in _install) {
install_component (stanza, zipfile);

// TODO: We should just *serialise* our current state, not
// copy the original file, because we can't always guarantee
// there will be an original file.

// TODO: This will just throw them in GameData.
// We need a way to convert stanzas to install locations.
// We really should make Stanza its own class.

File.Copy (origCkanFile, KSP.gameData() + "/" + _identifier + ".ckan", true);
}

// Finish now if we have no bundled mods.
if (_bundles == null) { return; }

// Do the same with our bundled mods.
foreach (dynamic stanza in _bundles) {

// TODO: Check versions, so we don't double install.

install_component (stanza, zipfile);

// TODO: Generate CKAN metadata for the bundled component.
}

return;

}

void install_component(dynamic stanza, ZipFile zipfile) {
string fileToInstall = stanza.file;

Console.WriteLine (" * Installing " + fileToInstall);

string[] path = fileToInstall.Split('/');

// TODO: This will depend upon the `install_to` in the JSON file
string installDir = KSP.gameData ();

// This is what we strip off paths
string stripDir = String.Join("/", path.Take(path.Count() - 1)) + "/";

// Console.WriteLine("InstallDir is "+installDir);
// Console.WriteLine ("StripDir is " + stripDir);

// This is awful. There's got to be a better way to extract a tree?
string filter = "^" + stanza.file + "(/|$)";

// O(N^2) solution. Surely there's a better way...
foreach (ZipEntry entry in zipfile) {

// Skip things we don't want.
if (! Regex.IsMatch (entry.Name, filter)) {
continue;
}

// Get the full name of the file.
string outputName = entry.Name;

// Strip off the prefix (often GameData/)
// TODO: The C# equivalent of "\Q stripDir \E" so we can't be caught by metacharacters.
outputName = Regex.Replace (outputName, @"^" + stripDir, "");

// Aww hell yes, let's write this file out!

string fullPath = Path.Combine (installDir, outputName);
// Console.WriteLine (fullPath);

copyZipEntry (zipfile, entry, fullPath);
}

return;
public string standard_name ()
{
return identifier + "-" + version + ".zip";
}

// TODO: Test that this actually throws exceptions if it can't do its job.
void copyZipEntry(ZipFile zipfile, ZipEntry entry, string fullPath) {

if (entry.IsDirectory) {
// Console.WriteLine ("Making directory " + fullPath);
Directory.CreateDirectory (fullPath);
}
else {
// Console.WriteLine ("Writing file " + fullPath);

// It's a file! Prepare the streams
Stream zipStream = zipfile.GetInputStream(entry);
FileStream output = File.Create (fullPath);

// Copy
zipStream.CopyTo (output);

// Tidy up.
zipStream.Close();
output.Close();
}

return;

public string serialise ()
{
return JsonConvert.SerializeObject (this);
}
}
}

}
8 changes: 4 additions & 4 deletions CKAN/CKAN/ModuleDict.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ public ModuleDict () {
string module = Regex.Replace (file, "^.*/([^.]+).*", "$1");

this [module] = new Module ();
this [module]._version = "0"; // We can say it exists, but have no idea of other info.
this [module]._identifier = module;
this [module].version = "0"; // We can say it exists, but have no idea of other info.
this [module].identifier = module;

// Console.WriteLine (this[module]._identifier + " ( " + file + " ) ");
}
Expand All @@ -59,7 +59,7 @@ public ModuleDict () {
foreach (string file in ckanFiles) {
Module module = Module.from_file (file);

this [module._identifier] = module;
this [module.identifier] = module;

// Console.WriteLine (module._identifier + " " + module._version + " ( " + file + " ) ");

Expand All @@ -69,7 +69,7 @@ public ModuleDict () {

public void showInstalled() {
foreach(KeyValuePair<string, Module> entry in this) {
Console.WriteLine (entry.Value._identifier + " " + entry.Value._version);
Console.WriteLine (entry.Value.identifier + " " + entry.Value.version);
}

return;
Expand Down
Loading