diff --git a/src/haxelib/SiteApi.hx b/src/haxelib/SiteApi.hx index e9b3ffeb..d815a7ca 100644 --- a/src/haxelib/SiteApi.hx +++ b/src/haxelib/SiteApi.hx @@ -22,6 +22,7 @@ package haxelib; import haxelib.MetaData; +import haxelib.Data.Dependencies; import haxe.ds.*; interface SiteApi { @@ -34,6 +35,7 @@ interface SiteApi { public function checkDeveloper( prj : String, user : String ) : Void; public function checkPassword( user : String, pass : String ) : Bool; public function getSubmitId() : String; + public function checkDependencies( dependencies : Dependencies) : Void; public function processSubmit( id : String, user : String, pass : String ) : String; diff --git a/src/haxelib/api/Connection.hx b/src/haxelib/api/Connection.hx index 50a7439d..991735c5 100644 --- a/src/haxelib/api/Connection.hx +++ b/src/haxelib/api/Connection.hx @@ -323,7 +323,7 @@ class Connection { } #end - static function retry(func:Void->R) { + static function retry(func:Void->R, errorPrefix = "Failed with error: ") { var hasRetried = false; var numTries = retries; @@ -339,7 +339,7 @@ class Connection { if (e == "std@host_resolve") Util.rethrow(e); if (e != "Blocked") - throw 'Failed with error: $e'; + throw errorPrefix + e; log("Failed. Triggering retry due to HTTP timeout"); hasRetried = true; } @@ -418,16 +418,6 @@ class Connection { uploadAndSubmit(user, data, logUploadStatus); } - static function checkDependencies(dependencies:Dependencies) { - for (name => versionString in dependencies) { - final versions:Array = getVersions(ProjectName.ofString(name)); - if (versionString == "") - continue; - if (!versions.contains(versionString)) - throw "Library " + name + " does not have version " + versionString; - } - } - static function doesVersionExist(library:ProjectName, version:SemVer):Bool { final versions = try getVersions(library) catch (_:Dynamic) return false; return versions.contains(version); @@ -537,11 +527,14 @@ class Connection { return retry(data.site.checkPassword.bind(userName, password)); static function checkDeveloper(library:ProjectName, userName:String) - return retry(data.site.checkDeveloper.bind(library, userName)); + return retry(data.site.checkDeveloper.bind(library, userName), ""); static function getSubmitId() return retry(data.site.getSubmitId.bind()); static function processSubmit(id:String, userName:String, password:String) return retry(data.site.processSubmit.bind(id, userName, password)); + + static function checkDependencies(dependencies:Dependencies) + return retry(data.site.checkDependencies.bind(dependencies), ""); } diff --git a/src/haxelib/server/Repo.hx b/src/haxelib/server/Repo.hx index bac1b6a5..6d8fb7a2 100644 --- a/src/haxelib/server/Repo.hx +++ b/src/haxelib/server/Repo.hx @@ -154,6 +154,27 @@ class Repo implements SiteApi { return Std.string(Std.random(100000000)); } + public function checkDependencies(dependencies:Dependencies) : Void { + for (dependency in dependencies.getNames()) { + var project = Project.manager.select($name == dependency); + if (project == null) { + throw 'Library $dependency does not exist'; + } + var version = Reflect.field(dependencies, dependency); + if (version == '') + continue; + var hasVersion = false; + for (versionObject in Version.manager.search($project == project.id)) { + if (versionObject.name == version) { + hasVersion = true; + } + } + if (!hasVersion) { + throw 'Library $dependency does not have version $version'; + } + } + } + public function processSubmit( id : String, user : String, pass : String ) : String { neko.Web.logMessage("processSubmit " + id); var tmpFile = Path.join([TMP_DIR_NAME, Std.parseInt(id)+".tmp"]); @@ -170,6 +191,13 @@ class Repo implements SiteApi { var infos = Data.readDataFromZip(zip,CheckData); neko.Web.logMessage("processSubmit " + id + " readDataFromZip completed"); + Data.checkClassPath(zip, infos); + Data.checkDocumentation(zip, infos); + + neko.Web.logMessage("processSubmit " + id + " metadata validation completed"); + + checkDependencies(infos.dependencies); + Manager.cnx.startTransaction(); var u = User.manager.search({ name : user }).first(); diff --git a/test/libraries/libMissingDep/haxelib.json b/test/libraries/libMissingDep/haxelib.json new file mode 100644 index 00000000..72ea22ae --- /dev/null +++ b/test/libraries/libMissingDep/haxelib.json @@ -0,0 +1,13 @@ +{ + "name": "Foo", + "url" : "http://example.org", + "license": "GPL", + "tags": ["foo", "test"], + "description": "This project depends on a library that doesn't exist on the server", + "version": "1.0.0", + "releasenote": "", + "dependencies": { + "MissingDep": "" + }, + "contributors": ["Foo"] +} diff --git a/test/libraries/libMissingDepVersion/haxelib.json b/test/libraries/libMissingDepVersion/haxelib.json new file mode 100644 index 00000000..0b63e76c --- /dev/null +++ b/test/libraries/libMissingDepVersion/haxelib.json @@ -0,0 +1,13 @@ +{ + "name": "Foo", + "url" : "http://example.org", + "license": "GPL", + "tags": ["foo", "test"], + "description": "This project depends on a version of Bar that doesn't exist on the server", + "version": "1.0.0", + "releasenote": "", + "dependencies": { + "Bar": "2.0.0" + }, + "contributors": ["Foo"] +} diff --git a/test/tests/integration/TestSubmit.hx b/test/tests/integration/TestSubmit.hx index 159a03d0..4b736bc8 100644 --- a/test/tests/integration/TestSubmit.hx +++ b/test/tests/integration/TestSubmit.hx @@ -46,6 +46,40 @@ class TestSubmit extends IntegrationTests { } } + function testLibraryWithMissingDep() { + final r = haxelib(["register", foo.user, foo.email, foo.fullname, foo.pw, foo.pw]).result(); + assertSuccess(r); + + final r = haxelib(["submit", Path.join([IntegrationTests.projectRoot, "test/libraries/libMissingDep.zip"]), foo.pw]).result(); + assertFail(r); + assertEquals("Error: Library MissingDep does not exist", r.err.trim()); + + final r = haxelib(["search", "Foo"]).result(); + // did not get submitted + assertFalse(r.out.indexOf("Foo") >= 0); + } + + function testLibraryWithMissingDepVersion() { + final r = haxelib(["register", bar.user, bar.email, bar.fullname, bar.pw, bar.pw]).result(); + assertSuccess(r); + + final r = haxelib(["submit", Path.join([IntegrationTests.projectRoot, "test/libraries/libBar.zip"]), bar.pw]).result(); + assertSuccess(r); + + final r = haxelib(["register", foo.user, foo.email, foo.fullname, foo.pw, foo.pw]).result(); + assertSuccess(r); + + final r = haxelib(["submit", Path.join([IntegrationTests.projectRoot, "test/libraries/libMissingDepVersion.zip"]), foo.pw]).result(); + assertFail(r); + assertEquals("Error: Library Bar does not have version 2.0.0", r.err.trim()); + + trace("hello"); + + final r = haxelib(["search", "Foo"]).result(); + // did not get submitted + assertFalse(r.out.indexOf("Foo") >= 0); + } + function testLibraryWithGitDep() { // git deps should not be allowed in published versions // https://github.com/HaxeFoundation/haxelib/pull/344#issuecomment-244006799