diff --git a/haxelib.json b/haxelib.json index 527508941..5c63c7218 100644 --- a/haxelib.json +++ b/haxelib.json @@ -9,6 +9,6 @@ "releasenote": " * Fixed too strict requirements to haxelib.json data for private libs (#484)", "contributors": ["HaxeFoundation", "back2dos", "ncannasse", "jason", "Simn", "nadako", "andyli"], "dependencies":{ - "hx3compat":"git:https://github.com/haxefoundation/hx3compat.git#f1f18201e5c0479cb5adf5f6028788b37f37b730" + "hx3compat": "" } } diff --git a/src/haxelib/Data.hx b/src/haxelib/Data.hx index 0ec26035a..ef0411b2b 100644 --- a/src/haxelib/Data.hx +++ b/src/haxelib/Data.hx @@ -20,63 +20,19 @@ * DEALINGS IN THE SOFTWARE. */ package haxelib; +/** + Contains definitions and functions for the data held in the haxelib.json file of a project. +**/ import haxe.ds.Option; -import haxe.ds.*; import haxe.zip.Reader; import haxe.zip.Entry; import haxe.Json; import haxelib.Validator; +import haxelib.Util; using StringTools; - -/** Information on a `user` in the Haxelib database. **/ -typedef UserInfos = { - /** The user's name. **/ - var name : String; - /** The user's full name. **/ - var fullname : String; - /** The user's email address. **/ - var email : String; - /** An array of projects for which the user is a contributor. **/ - var projects : Array; -} - -/** Information on a specific version of a project in the Haxelib database. **/ -typedef VersionInfos = { - /** The release date of the version. **/ - var date : String; - /** The version "name" in SemVer form. **/ - var name : SemVer;//TODO: this should eventually be called `number` - /** The number of downloads this version of the library has had. **/ - var downloads : Int; - /** The release note that came with this release. **/ - var comments : String; -} - -/** Information on a project in the Haxelib database. **/ -typedef ProjectInfos = { - /** The project name. **/ - var name : String; - /** The project's description. **/ - var desc : String; - /** A link to the project's website. **/ - var website : String; - /** The username of the owner of the project. **/ - var owner : String; - /** An array of contributor's user names and full names. **/ - var contributors : Array<{ name:String, fullname:String }>; - /** The license under which the project is released. **/ - var license : String; - /** The current version of the project. **/ - var curversion : String; - /** The total number of downloads the project has. **/ - var downloads : Int; - /** An array of `VersionInfos` for each release of the library. **/ - var versions : Array; - /** The project's tags. **/ - var tags : List; -} +using Lambda; /** The level of strictness with which a `haxelib.json` check is performed. **/ @:enum abstract CheckLevel(Int) { @@ -84,12 +40,12 @@ typedef ProjectInfos = { var NoCheck = 0; /** Only the syntax of the file is checked. **/ var CheckSyntax = 1; - /** The syntax is checked and data in the file is validated. **/ - var CheckData = 2; + /** + The syntax is checked and data in the file is validated. - @:from static inline function fromBool(check:Bool):CheckLevel { - return check ? CheckData : NoCheck; - } + Data must meet the requirements for publishing to the server. + **/ + var CheckData = 2; @:op(A > B) function gt(b:CheckLevel):Bool; @:op(A >= B) function gte(b:CheckLevel):Bool; @@ -105,14 +61,25 @@ abstract DependencyVersion(String) to String from SemVer { @:to function toValidatable():Validatable return - if (this == DEFAULT || this == GIT || (#if (haxe_ver < 4.1) Std.is #else Std.isOfType #end(this, String) && this.startsWith('git:'))) + if (this == DEFAULT) { validate: function () return None } + else if (#if (haxe_ver < 4.1) Std.is(this, String) #else this is String #end && this.split(":")[0] == GIT ) + {validate: function() return Some("Git dependency is not allowed in a library release")} else @:privateAccess new SemVer(this); /** Returns whether `s` constitutes a valid dependency version string. **/ static public function isValid(s:String):Bool - return new DependencyVersion(s).toValidatable().validate() == None; + return s == DEFAULT || SemVer.isValid(s); + + /** + Returns whether `s` constitutes dependency version string that can be used locally. + + The requirements for this are not as strict as `isValid()`, as vcs + dependencies are allowed. + **/ + static public function isUsable(s:String):Bool + return #if (haxe_ver < 4.1) Std.is(s, String) #else (s is String) #end && s.split(":")[0] == GIT || isValid(s); /** Default empty dependency version. **/ static public var DEFAULT(default, null) = new DependencyVersion(''); @@ -230,6 +197,8 @@ typedef Infos = { var Bsd = 'BSD'; var Public = 'Public'; var Apache = 'Apache'; + @:disallowed + var Unknown = 'Unknown'; } /** Class providing functions for working with project information. **/ @@ -264,28 +233,6 @@ class Data { return safe(lib)+"-"+safe(ver)+".zip"; } - /** - Returns the latest version from `info`, or `null` if no releases are found. - - By default preview versions are ignored. If `preview` is passed in, - preview versions will be checked first and will only be skipped - if calling `preview` with the `Preview` type of the version, - and it is only skipped if the call returns `false`. - **/ - static public function getLatest(info:ProjectInfos, ?preview:SemVer.Preview->Bool):Null { - if (info.versions.length == 0) return null; - if (preview == null) - preview = function (p) return p == null; - - var versions = info.versions.copy(); - versions.sort(function (a, b) return -SemVer.compare(a.name, b.name)); - - for (v in versions) - if (preview(v.name.preview)) return v.name; - - return versions[0].name; - } - /** Returns the directory that contains *haxelib.json*. If it is at the root, `""`. @@ -333,7 +280,7 @@ class Data { } /** Retrieves the haxelib.json data from `zip`, validating it according to `check`. **/ - public static function readInfos( zip : List, check : CheckLevel ) : Infos + public static function readDataFromZip( zip : List, check : CheckLevel ) : Infos return readData(Reader.unzip(getJson(zip)).toString(), check); /** Throws an exception if the classpath in `infos` does not exist in `zip`. **/ @@ -350,6 +297,28 @@ class Data { } } + static function cleanDependencies(dependencies:Null):Void { + if (dependencies == null) + return; + #if haxe4 + for (name => version in dependencies) { + if (!DependencyVersion.isUsable(version)) + Reflect.setField(dependencies, name, DependencyVersion.DEFAULT); // TODO: this is pure evil + } + #else + for (name in dependencies.getNames()) { + if (!DependencyVersion.isUsable(Reflect.field(dependencies, name))) + Reflect.setField(dependencies, name, DependencyVersion.DEFAULT); // TODO: this is pure evil + } + #end + } + + static inline function isStringArray(array:Array) { + return #if (haxe_ver < 4.1) Std.is(array, Array) && array.foreach(function(item) { return Std.is(item, String);}); + #else (array is Array) && array.foreach((item) -> item is String); + #end + } + /** Extracts project information from `jsondata`, validating it according to `check`. @@ -369,41 +338,40 @@ class Data { url : '', version : SemVer.DEFAULT, releasenote: 'No haxelib.json found', - license: Mit, + license: Unknown, description: 'No haxelib.json found', contributors: [], } - if (check >= CheckLevel.CheckData) + if (check >= CheckLevel.CheckData) { Validator.validate(doc); - else { + } else { + if (doc.name.validate() != None) + doc.name = defaultName; if (!doc.version.valid) doc.version = SemVer.DEFAULT; + if (doc.license == null || doc.license == '') + doc.license = Unknown; + if (!isStringArray(doc.contributors)) + doc.contributors = []; + if (doc.releasenote == null) + doc.releasenote = ''; + cleanDependencies(doc.dependencies); } //TODO: we have really weird ways to go about nullability and defaults + // these may have been ommitted even in a valid file if (doc.dependencies == null) doc.dependencies = {}; - - for (dep in doc.dependencies) - if (!DependencyVersion.isValid(dep.version)) - Reflect.setField(doc.dependencies, dep.name, DependencyVersion.DEFAULT);//TODO: this is pure evil - if (doc.classPath == null) doc.classPath = ''; - - if (doc.name.validate() != None) - doc.name = defaultName; - if (doc.description == null) doc.description = ''; - - if (doc.tags == null) - doc.tags = []; - if (doc.url == null) doc.url = ''; + if (!isStringArray(doc.tags)) + doc.tags = []; return doc; } diff --git a/src/haxelib/MetaData.hx b/src/haxelib/MetaData.hx new file mode 100644 index 000000000..84d0a18b2 --- /dev/null +++ b/src/haxelib/MetaData.hx @@ -0,0 +1,78 @@ +package haxelib; +/** + Contains definitions of meta data about libraries and their versions used in the Haxelib database +**/ + +/** Information on a `user` in the Haxelib database. **/ +typedef UserInfos = { + /** The user's name. **/ + var name : String; + /** The user's full name. **/ + var fullname : String; + /** The user's email address. **/ + var email : String; + /** An array of projects for which the user is a contributor. **/ + var projects : Array; +} + +/** Information on a specific version of a project in the Haxelib database. **/ +typedef VersionInfos = { + /** The release date of the version. **/ + var date : String; + /** The version "name" in SemVer form. **/ + var name : SemVer;//TODO: this should eventually be called `number` + /** The number of downloads this version of the library has had. **/ + var downloads : Int; + /** The release note that came with this release. **/ + var comments : String; +} + +/** Information on a project in the Haxelib database. **/ +typedef ProjectInfos = { + /** The project name. **/ + var name : String; + /** The project's description. **/ + var desc : String; + /** A link to the project's website. **/ + var website : String; + /** The username of the owner of the project. **/ + var owner : String; + /** An array of contributor's user names and full names. **/ + var contributors : Array<{ name:String, fullname:String }>; + /** The license under which the project is released. **/ + var license : String; + /** The current version of the project. **/ + var curversion : String; + /** The total number of downloads the project has. **/ + var downloads : Int; + /** An array of `VersionInfos` for each release of the library. **/ + var versions : Array; + /** The project's tags. **/ + var tags : List; +} + +class MetaData { + /** + Returns the latest version from `info`, or `null` if no releases are found. + + By default preview versions are ignored. If `preview` is passed in, + preview versions will be checked first and will only be skipped + if calling `preview` with the `Preview` type of the version, + and it is only skipped if the call returns `false`. + **/ + public static function getLatest(info:ProjectInfos, ?preview:SemVer.Preview->Bool):Null { + if (info.versions.length == 0) + return null; + if (preview == null) + preview = function(p) return p == null; + + var versions = info.versions.copy(); + versions.sort(function(a, b) return -SemVer.compare(a.name, b.name)); + + for (v in versions) + if (preview(v.name.preview)) + return v.name; + + return versions[0].name; + } +} diff --git a/src/haxelib/SiteApi.hx b/src/haxelib/SiteApi.hx index d0e4bbda6..e9b3ffebb 100644 --- a/src/haxelib/SiteApi.hx +++ b/src/haxelib/SiteApi.hx @@ -21,7 +21,7 @@ */ package haxelib; -import haxelib.Data; +import haxelib.MetaData; import haxe.ds.*; interface SiteApi { diff --git a/src/haxelib/Util.hx b/src/haxelib/Util.hx index d9603851b..3eb421013 100644 --- a/src/haxelib/Util.hx +++ b/src/haxelib/Util.hx @@ -28,30 +28,30 @@ class Util { macro static public function getHaxelibVersionLong() { var version:String = readVersionFromHaxelibJson(); + // check if the .git folder exist + // prevent getting the git info of a parent directory + if (!sys.FileSystem.isDirectory(".git")) + return macro $v{version}; + var p; try { - //check if the .git folder exist - //prevent getting the git info of a parent directory - if (!sys.FileSystem.isDirectory(".git")) - throw "Not a git repo."; - //get commit sha p = new sys.io.Process("git", ["rev-parse", "HEAD"]); - final sha = p.stdout.readAll().toString().trim(); + var sha = p.stdout.readAll().toString().trim(); p.close(); //check to see if there is changes, staged or not p = new sys.io.Process("git", ["status", "--porcelain"]); - final changes = p.stdout.readAll().toString().trim(); + var changes = p.stdout.readAll().toString().trim(); p.close(); - version += switch(changes) { + var longVersion = version + switch(changes) { case "": ' ($sha)'; case _: ' ($sha - dirty)'; } - return macro $v{version}; + return macro $v{longVersion}; } catch(e:Dynamic) { if (p != null) p.close(); return macro $v{version}; diff --git a/src/haxelib/Validator.hx b/src/haxelib/Validator.hx index 7324e53bd..02273cd6f 100644 --- a/src/haxelib/Validator.hx +++ b/src/haxelib/Validator.hx @@ -144,7 +144,7 @@ class Validator { var name = a.module + '.' + a.name; var options:Array = [ for (f in a.impl.get().statics.get()) - if (f.kind.match(FVar(_, _))) + if (f.kind.match(FVar(_, _)) && !f.meta.has(':disallowed')) macro @:pos(pos) $p{(name+'.'+f.name).split('.')} ]; diff --git a/src/haxelib/api/Connection.hx b/src/haxelib/api/Connection.hx index 9c6e3b81f..67c8ed6f4 100644 --- a/src/haxelib/api/Connection.hx +++ b/src/haxelib/api/Connection.hx @@ -11,6 +11,7 @@ import sys.FileSystem; import sys.io.File; import haxelib.Data; +import haxelib.MetaData; using StringTools; @@ -398,7 +399,7 @@ class Connection { zip = Reader.readZip(new haxe.io.BytesInput(data)); } - final infos = Data.readInfos(zip, true); + final infos = Data.readDataFromZip(zip, CheckData); Data.checkClassPath(zip, infos); // ask user which contributor they are diff --git a/src/haxelib/api/GlobalScope.hx b/src/haxelib/api/GlobalScope.hx index db166a979..daae62e76 100644 --- a/src/haxelib/api/GlobalScope.hx +++ b/src/haxelib/api/GlobalScope.hx @@ -28,7 +28,7 @@ class GlobalScope extends Scope { final resolved = resolveVersionAndPath(library, version); final info = - try Data.readData(File.getContent(resolved.path + Data.JSON), false) + try Data.readData(File.getContent(resolved.path + Data.JSON), NoCheck) catch (e:Dynamic) throw 'Failed when trying to parse haxelib.json for $library@${resolved.version}: $e'; diff --git a/src/haxelib/api/Installer.hx b/src/haxelib/api/Installer.hx index 788efc664..1cb7f57e3 100644 --- a/src/haxelib/api/Installer.hx +++ b/src/haxelib/api/Installer.hx @@ -3,6 +3,7 @@ package haxelib.api; import sys.FileSystem; import sys.io.File; +import haxelib.Data; import haxelib.api.Repository; import haxelib.api.Vcs; import haxelib.api.LibraryData; @@ -10,7 +11,7 @@ import haxelib.api.LibFlagData; using StringTools; using Lambda; -using haxelib.Data; +using haxelib.MetaData; /** Exception thrown when an error occurs during installation. **/ class InstallationException extends haxe.Exception {} @@ -199,7 +200,7 @@ class Installer { // read zip content final zip = FsUtils.unzip(path); - final info = Data.readInfos(zip, false); + final info = Data.readDataFromZip(zip, NoCheck); final library = info.name; final version = info.version; @@ -231,7 +232,7 @@ class Installer { final path = FileSystem.fullPath(path); userInterface.log('Installing libraries from $path'); - final dependencies = Data.readData(File.getContent(path), false).dependencies; + final dependencies = Data.readData(File.getContent(path), NoCheck).dependencies; try installFromDependencies(dependencies) @@ -468,7 +469,7 @@ class Installer { if (!FileSystem.exists(jsonPath)) return {}; - return switch (Data.readData(File.getContent(jsonPath), false).dependencies) { + return switch (Data.readData(File.getContent(jsonPath), NoCheck).dependencies) { case null: {}; case dependencies: dependencies; } @@ -484,7 +485,7 @@ class Installer { final jsonPath = scope.getPath(givenName, id) + (if (subDir != null) subDir else "") + Data.JSON; if (!FileSystem.exists(jsonPath)) return givenName; - final internalName = Data.readData(File.getContent(jsonPath), false).name; + final internalName = Data.readData(File.getContent(jsonPath), NoCheck).name; return ProjectName.getCorrectOrAlias(internalName, givenName); } diff --git a/src/haxelib/client/Main.hx b/src/haxelib/client/Main.hx index ed0fdc748..4e1cd2091 100644 --- a/src/haxelib/client/Main.hx +++ b/src/haxelib/client/Main.hx @@ -36,7 +36,7 @@ import haxelib.Util.rethrow; using StringTools; using Lambda; -using haxelib.Data; +using haxelib.MetaData; using haxelib.api.RepoReformatter; @:structInit @@ -719,7 +719,7 @@ class Main { if (!FileSystem.exists(jsonPath)) project; else { - final internalName = Data.readData(File.getContent(jsonPath), false).name; + final internalName = Data.readData(File.getContent(jsonPath), NoCheck).name; ProjectName.getCorrectOrAlias(internalName, project); } } diff --git a/src/haxelib/server/Repo.hx b/src/haxelib/server/Repo.hx index c050fad0d..75c481798 100644 --- a/src/haxelib/server/Repo.hx +++ b/src/haxelib/server/Repo.hx @@ -26,6 +26,7 @@ import sys.io.*; import sys.*; import haxelib.Data; +import haxelib.MetaData; import haxelib.SemVer; import haxelib.server.Paths.*; import haxelib.server.SiteDb; @@ -161,7 +162,7 @@ class Repo implements SiteApi { var zip = try haxe.zip.Reader.readZip(file) catch( e : Dynamic ) { file.close(); #if neko neko.Lib.rethrow(e); #else throw e; #end }; file.close(); - var infos = Data.readInfos(zip,true); + var infos = Data.readDataFromZip(zip,CheckData); var u = User.manager.search({ name : user }).first(); if( u == null || u.pass != pass ) throw "Invalid username or password"; diff --git a/src/website/api/ProjectApi.hx b/src/website/api/ProjectApi.hx index 150b484d4..2130e702a 100644 --- a/src/website/api/ProjectApi.hx +++ b/src/website/api/ProjectApi.hx @@ -4,6 +4,7 @@ import haxe.io.Bytes; import haxe.zip.Entry; import haxe.zip.Reader; import haxelib.Data; +import haxelib.MetaData; import haxelib.server.FileStorage; import haxelib.server.Repo; import haxelib.server.Paths.*; diff --git a/test/libraries/libFooGitDep/foo/Foo.hx b/test/libraries/libFooGitDep/foo/Foo.hx new file mode 100644 index 000000000..fb407cba0 --- /dev/null +++ b/test/libraries/libFooGitDep/foo/Foo.hx @@ -0,0 +1,9 @@ +package foo; + +class Foo { + + public function new() { + trace("new Foo"); + } + +} diff --git a/test/libraries/libFooGitDep/haxelib.json b/test/libraries/libFooGitDep/haxelib.json new file mode 100644 index 000000000..48035d144 --- /dev/null +++ b/test/libraries/libFooGitDep/haxelib.json @@ -0,0 +1,13 @@ +{ + "name": "Foo", + "url" : "http://example.org", + "license": "GPL", + "tags": ["foo", "test"], + "description": "This project is an example of an haxelib project", + "version": "1.0.0", + "releasenote": "Initial release, everything is working correctly", + "dependencies": { + "Bar": "git:./libraries/libBar" + }, + "contributors": ["Foo"] +} diff --git a/test/libraries/libInvalidLicense/Main.hx b/test/libraries/libInvalidLicense/Main.hx new file mode 100644 index 000000000..93c03cf9a --- /dev/null +++ b/test/libraries/libInvalidLicense/Main.hx @@ -0,0 +1,3 @@ +function main() { + trace("Hello, world!"); +} diff --git a/test/libraries/libInvalidLicense/haxelib.json b/test/libraries/libInvalidLicense/haxelib.json new file mode 100644 index 000000000..b6f8c15d0 --- /dev/null +++ b/test/libraries/libInvalidLicense/haxelib.json @@ -0,0 +1,10 @@ +{ + "name": "Bar", + "url" : "http://example.org", + "license": "Unknown", + "tags": ["bar", "test"], + "description": "This project is an example of an haxelib project", + "version": "1.0.0", + "releasenote": "Initial release, everything is working correctly", + "contributors": ["Bar"] +} diff --git a/test/tests/TestData.hx b/test/tests/TestData.hx index c0473dc78..d7ba5c641 100644 --- a/test/tests/TestData.hx +++ b/test/tests/TestData.hx @@ -64,14 +64,14 @@ class TestData extends TestBase { //TODO } - public function testReadInfos() { + public function testReadDataFromZip() { var zip = Reader.readZip(new BytesInput(File.getBytes("package.zip"))); - var info = Data.readInfos(zip, true); + var info = Data.readDataFromZip(zip, CheckData); assertEquals( "haxelib", info.name ); assertEquals( "MIT", info.license ); var zip = Reader.readZip(new BytesInput(File.getBytes("test/libraries/libDeep.zip"))); - var info = Data.readInfos(zip, true); + var info = Data.readDataFromZip(zip, CheckData); assertEquals( "Deep", info.name ); assertEquals( "http://example.org", info.url ); assertEquals( "Public", info.license ); @@ -84,7 +84,7 @@ class TestData extends TestBase { public function testCheckClassPath() { var zip = Reader.readZip(new BytesInput(File.getBytes("package.zip"))); - var info = Data.readInfos(zip, true); + var info = Data.readDataFromZip(zip, CheckData); var ok:Dynamic = try { Data.checkClassPath(zip,info); true; @@ -94,7 +94,7 @@ class TestData extends TestBase { assertEquals( ok, true ); var zip = Reader.readZip(new BytesInput(File.getBytes("test/libraries/libDeep.zip"))); - var info = Data.readInfos(zip, true); + var info = Data.readDataFromZip(zip, CheckData); var ok:Dynamic = try { Data.checkClassPath(zip,info); true; @@ -104,7 +104,7 @@ class TestData extends TestBase { assertEquals( ok, true ); } - public function testReadDataWithCheck() { + public function testReadDataWithDataCheck() { assertFalse( readDataOkay("bad json") ); assertTrue( readDataOkay(getJsonInfos()) ); @@ -133,6 +133,7 @@ class TestData extends TestBase { assertFalse( readDataOkay(getJsonInfos({ license: null })) ); assertFalse( readDataOkay(getJsonInfos({ license: '' })) ); assertFalse( readDataOkay(getJsonInfos({ license: 'CustomLicence' })) ); + assertFalse(readDataOkay(getJsonInfos({license: 'Unknown'}))); assertFalse( readDataOkay(getJsonInfos([ "license" ])) ); // remove the field altogether // Contibutors @@ -161,6 +162,8 @@ class TestData extends TestBase { assertTrue( readDataOkay(getJsonInfos({ dependencies: { somelib:"1.3.0" } }) )); assertFalse( readDataOkay(getJsonInfos({ dependencies: { somelib: "nonsemver" }})) ); + assertFalse(readDataOkay(getJsonInfos({dependencies: {somelib: "git"}}))); + assertFalse(readDataOkay(getJsonInfos({dependencies: {somelib: "git:https://some.url"}}))); assertFalse( readDataOkay(getJsonInfos({ dependencies: { somelib: 0 } })) ); assertFalse( readDataOkay(getJsonInfos({ dependencies: "somelib" })) ); @@ -179,74 +182,79 @@ class TestData extends TestBase { } public function testReadDataWithoutCheck() { - assertEquals( ProjectName.DEFAULT, Data.readData("bad json",false).name ); - assertEquals( "0.0.0", Data.readData("bad json",false).version ); + assertEquals(ProjectName.DEFAULT, Data.readData("bad json", NoCheck).name); + assertEquals("0.0.0", Data.readData("bad json", NoCheck).version); - assertEquals( "mylib", Data.readData(getJsonInfos(),false).name ); - assertEquals( "0.1.2", Data.readData(getJsonInfos(),false).version ); + assertEquals("mylib", Data.readData(getJsonInfos(), NoCheck).name); + assertEquals("0.1.2", Data.readData(getJsonInfos(), NoCheck).version); // Names - assertEquals( ProjectName.DEFAULT, Data.readData("{}",false).name ); - assertEquals( ProjectName.DEFAULT, Data.readData(getJsonInfos({ name: null }),false).name ); - assertEquals( ProjectName.DEFAULT, Data.readData(getJsonInfos({ name: '' }),false).name ); - assertEquals( "mylib", Data.readData(getJsonInfos({ name: 'mylib' }),false).name ); - assertEquals( ProjectName.DEFAULT, Data.readData(getJsonInfos([ "name" ]), false).name ); // remove the field altogether + assertEquals(ProjectName.DEFAULT, Data.readData("{}", NoCheck).name); + assertEquals(ProjectName.DEFAULT, Data.readData(getJsonInfos({name: null}), NoCheck).name); + assertEquals(ProjectName.DEFAULT, Data.readData(getJsonInfos({name: ''}), NoCheck).name); + assertEquals("mylib", Data.readData(getJsonInfos({name: 'mylib'}), NoCheck).name); + assertEquals(ProjectName.DEFAULT, Data.readData(getJsonInfos(["name"]), NoCheck).name); // remove the field altogether - /* // Description (optional) - assertEquals( "Some Description", Data.readData(getJsonInfos({ description: 'Some Description' }),false).description ); - assertEquals( "", Data.readData(getJsonInfos({ description: '' }),false).description ); - assertEquals( "", Data.readData(getJsonInfos({ description: null }),false).description ); - assertEquals( "", Data.readData(getJsonInfos([ "description" ]),false).description ); // remove the field altogether + assertEquals("Some Description", Data.readData(getJsonInfos({description: 'Some Description'}), NoCheck).description); + assertEquals("", Data.readData(getJsonInfos({description: ''}), NoCheck).description); + assertEquals("", Data.readData(getJsonInfos({description: null}), NoCheck).description); + assertEquals("", Data.readData(getJsonInfos(["description"]), NoCheck).description); // remove the field altogether // Licence - assertEquals( "BSD", Data.readData(getJsonInfos({ license: 'BSD' }),false).license ); - assertEquals( "Unknown", Data.readData(getJsonInfos({ license: null }),false).license ); - assertEquals( "Unknown", Data.readData(getJsonInfos({ license: '' }),false).license ); - assertEquals( "CustomLicence", Data.readData(getJsonInfos({ license: 'CustomLicence' }),false).license ); - assertEquals( "Unknown", Data.readData(getJsonInfos([ "license" ]),false).license ); // remove the field altogether + assertEquals("BSD", Data.readData(getJsonInfos({license: 'BSD'}), NoCheck).license); + assertEquals("Unknown", Data.readData(getJsonInfos({license: null}), NoCheck).license); + assertEquals("Unknown", Data.readData(getJsonInfos({license: ''}), NoCheck).license); + assertEquals("CustomLicence", Data.readData(getJsonInfos({license: 'CustomLicence'}), NoCheck).license); + assertEquals("Unknown", Data.readData(getJsonInfos(["license"]), NoCheck).license); // remove the field altogether // Contibutors - assertEquals( 0, Data.readData(getJsonInfos({ contributors: [] }),false).contributors.length ); - assertEquals( 0, Data.readData(getJsonInfos({ contributors: null }),false).contributors.length ); - assertEquals( 0, Data.readData(getJsonInfos({ contributors: "jason" }),false).contributors.length ); - assertEquals( 1, Data.readData(getJsonInfos({ contributors: ["jason"] }),false).contributors.length ); - assertEquals( 2, Data.readData(getJsonInfos({ contributors: ["jason","juraj"] }),false).contributors.length ); - assertEquals( 0, Data.readData(getJsonInfos([ "contributors" ]),false).contributors.length ); // remove the field altogether - */ + assertEquals(0, Data.readData(getJsonInfos({contributors: []}), NoCheck).contributors.length); + assertEquals(0, Data.readData(getJsonInfos({contributors: null}), NoCheck).contributors.length); + assertEquals(0, Data.readData(getJsonInfos({contributors: "jason"}), NoCheck).contributors.length); + assertEquals(1, Data.readData(getJsonInfos({contributors: ["jason"]}), NoCheck).contributors.length); + assertEquals(2, Data.readData(getJsonInfos({contributors: ["jason", "juraj"]}), NoCheck).contributors.length); + assertEquals(0, Data.readData(getJsonInfos(["contributors"]), NoCheck).contributors.length); // remove the field altogether + // Version - assertEquals( "0.1.2-rc.0", Data.readData(getJsonInfos({ version: "0.1.2-rc.0" }),false).version ); - assertEquals( "0.0.0", Data.readData(getJsonInfos({ version: "non-semver" }),false).version ); - assertEquals( "0.0.0", Data.readData(getJsonInfos({ version: 0 }),false).version ); - assertEquals( "0.0.0", Data.readData(getJsonInfos({ version: null }),false).version ); - assertEquals( "0.0.0", Data.readData(getJsonInfos([ "version" ]),false).version ); // remove the field altogether + assertEquals("0.1.2-rc.0", Data.readData(getJsonInfos({version: "0.1.2-rc.0"}), NoCheck).version); + assertEquals("0.0.0", Data.readData(getJsonInfos({version: "non-semver"}), NoCheck).version); + assertEquals("0.0.0", Data.readData(getJsonInfos({version: 0}), NoCheck).version); + assertEquals("0.0.0", Data.readData(getJsonInfos({version: null}), NoCheck).version); + assertEquals("0.0.0", Data.readData(getJsonInfos(["version"]), NoCheck).version); // remove the field altogether - /* // Tags (optional) - assertEquals( 2, Data.readData(getJsonInfos({ tags: ["tag1","tag2"] }),false).tags.length ); - assertEquals( 0, Data.readData(getJsonInfos({ tags: null }),false).tags.length ); - assertEquals( 0, Data.readData(getJsonInfos({ tags: "mytag" }),false).tags.length ); - */ + assertEquals(2, Data.readData(getJsonInfos({tags: ["tag1", "tag2"]}), NoCheck).tags.length); + assertEquals(0, Data.readData(getJsonInfos({tags: null}), NoCheck).tags.length); + assertEquals(0, Data.readData(getJsonInfos({tags: "mytag"}), NoCheck).tags.length); // Dependencies (optional) - assertEquals( 0, Data.readData(getJsonInfos({ dependencies: null }),false).dependencies.toArray().length ); - assertEquals( "somelib", Data.readData(getJsonInfos({ dependencies: { somelib:"" } }),false).dependencies.toArray()[0].name ); - assertEquals( "", Data.readData(getJsonInfos({ dependencies: { somelib:"" } }),false).dependencies.toArray()[0].version ); - assertEquals( "1.3.0", Data.readData(getJsonInfos({ dependencies: { somelib:"1.3.0" } }),false).dependencies.toArray()[0].version ); - assertEquals( "", Data.readData(getJsonInfos({ dependencies: { somelib:"nonsemver" } }),false).dependencies.toArray()[0].version ); - assertEquals( "", Data.readData(getJsonInfos({ dependencies: { somelib:null } }),false).dependencies.toArray()[0].version ); - assertEquals( "", Data.readData(getJsonInfos( { dependencies: { somelib:0 } } ), false).dependencies.toArray()[0].version ); - - /* + inline function getFirstDependency(dependencies:Dynamic) + return Data.readData(getJsonInfos({dependencies: dependencies}), NoCheck).dependencies.toArray()[0]; + + assertEquals(0, Data.readData(getJsonInfos({dependencies: null}), NoCheck).dependencies.toArray().length); + assertEquals("somelib", getFirstDependency({somelib: ""}).name); + assertEquals("", getFirstDependency({somelib: ""}).version); + assertEquals("1.3.0", getFirstDependency({somelib: "1.3.0"}).version); + assertEquals("", getFirstDependency({somelib: "nonsemver"}).version); + assertEquals("", getFirstDependency({somelib: null}).version); + assertEquals("", getFirstDependency({somelib: 0}).version); + assertEquals("git", getFirstDependency({somelib: "git"}).version); + + final gitDependency = getFirstDependency({somelib: "git:https://some.url#branch"}); + assertEquals(Git, gitDependency.type); + assertEquals("https://some.url", gitDependency.url); + assertEquals("branch", gitDependency.branch); + // ReleaseNote - assertEquals( "release", Data.readData(getJsonInfos({ releasenote: "release" }),false).releasenote ); - assertEquals( "", Data.readData(getJsonInfos({ releasenote: null }),false).releasenote ); - assertEquals( "", Data.readData(getJsonInfos([ "releasenote" ]),false).releasenote ); // remove the field altogether - */ + assertEquals("release", Data.readData(getJsonInfos({releasenote: "release"}), NoCheck).releasenote); + assertEquals("", Data.readData(getJsonInfos({releasenote: null}), NoCheck).releasenote); + assertEquals("", Data.readData(getJsonInfos(["releasenote"]), NoCheck).releasenote); // remove the field altogether + // ClassPath - assertEquals( "src", Data.readData(getJsonInfos({ classPath: 'src' }), false).classPath ); - assertEquals( "", Data.readData(getJsonInfos({ classPath: '' }), false).classPath ); - assertEquals( "", Data.readData(getJsonInfos({ classPath: null }), false).classPath ); + assertEquals("src", Data.readData(getJsonInfos({classPath: 'src'}), NoCheck).classPath); + assertEquals("", Data.readData(getJsonInfos({classPath: ''}), NoCheck).classPath); + assertEquals("", Data.readData(getJsonInfos({classPath: null}), NoCheck).classPath); } function testAliasCheck() { @@ -267,7 +275,7 @@ class TestData extends TestBase { function readDataOkay( json ) { try { - Data.readData( json,true ); + Data.readData(json, CheckData); return true; } catch (e:String) { diff --git a/test/tests/TestInstaller.hx b/test/tests/TestInstaller.hx index b18e887d8..ccd9281f3 100644 --- a/test/tests/TestInstaller.hx +++ b/test/tests/TestInstaller.hx @@ -97,7 +97,7 @@ class TestInstaller extends TestBase { function getLibraryName():String { final haxelibFile = File.read("haxelib.json", false); - final details = Data.readData(haxelibFile.readAll().toString(), false ); + final details = Data.readData(haxelibFile.readAll().toString(), NoCheck); haxelibFile.close(); return details.dependencies.toArray()[0].name; } diff --git a/test/tests/integration/TestInstall.hx b/test/tests/integration/TestInstall.hx index 236fb9818..467b2864e 100644 --- a/test/tests/integration/TestInstall.hx +++ b/test/tests/integration/TestInstall.hx @@ -1,7 +1,11 @@ package tests.integration; +import tests.util.Vcs; + class TestInstall extends IntegrationTests { + final gitLibPath = "libraries/libBar"; + override function setup(){ super.setup(); @@ -18,6 +22,11 @@ class TestInstall extends IntegrationTests { assertSuccess(r); } + override function tearDown() { + resetGitRepo(gitLibPath); + super.tearDown(); + } + function testNormal():Void { { final r = haxelib(["install", "Bar"]).result(); @@ -189,4 +198,32 @@ class TestInstall extends IntegrationTests { assertSuccess(r); } } + + function testLocalWithInvalidLicense() { + // unknown license should not prevent install + final r = haxelib(["install", "libraries/libInvalidLicense.zip"]).result(); + assertSuccess(r); + + final r = haxelib(["list", "Bar"]).result(); + assertTrue(r.out.indexOf("Bar") >= 0); + assertSuccess(r); + } + + function testLocalWithGitDependency() { + // prepare git dependency + makeGitRepo(gitLibPath); + + final r = haxelib(["install", "libraries/libFooGitDep.zip"]).result(); + assertSuccess(r); + + final r = haxelib(["list", "Foo"]).result(); + assertTrue(r.out.indexOf("Foo") >= 0); + assertTrue(r.out.indexOf("[1.0.0]") >= 0); + assertSuccess(r); + + final r = haxelib(["list", "Bar"]).result(); + assertTrue(r.out.indexOf("Bar") >= 0); + assertTrue(r.out.indexOf("[git]") >= 0); + assertSuccess(r); + } } diff --git a/test/tests/integration/TestPath.hx b/test/tests/integration/TestPath.hx index ad263ea99..0991ed530 100644 --- a/test/tests/integration/TestPath.hx +++ b/test/tests/integration/TestPath.hx @@ -16,6 +16,17 @@ class TestPath extends IntegrationTests { assertFail(r); } #end + function testInvalidLicense() { + // invalid license should not prevent usage + final r = haxelib(["dev", "InvalidLicense", "libraries/libInvalidLicense"]).result(); + assertSuccess(r); + final r = haxelib(["path", "InvalidLicense"]).result(); + assertSuccess(r); + assertOutputEquals([ + Path.join([IntegrationTests.projectRoot, "test/libraries/libInvalidLicense"]).addTrailingSlash(), + "-D Bar=1.0.0" + ], r.out); + } function testMultipleLibraries():Void { final r = haxelib(["install", "libraries/libBar.zip"]).result(); diff --git a/test/tests/integration/TestSubmit.hx b/test/tests/integration/TestSubmit.hx index a34a5279b..6aca98bf4 100644 --- a/test/tests/integration/TestSubmit.hx +++ b/test/tests/integration/TestSubmit.hx @@ -1,6 +1,15 @@ package tests.integration; +import tests.util.Vcs; + class TestSubmit extends IntegrationTests { + final gitLibPath = "libraries/libBar"; + + override function tearDown() { + resetGitRepo(gitLibPath); + super.tearDown(); + } + function testNormal():Void { { final r = haxelib(["register", bar.user, bar.email, bar.fullname, bar.pw, bar.pw]).result(); @@ -34,4 +43,58 @@ class TestSubmit extends IntegrationTests { assertTrue(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 + + // first prepare the dependency + makeGitRepo(gitLibPath); + + { + 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(["search", "Bar"]).result(); + assertSuccess(r); + assertTrue(r.out.indexOf("Bar") >= 0); + } + + { + 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/libFooGitDep.zip"]), foo.pw]).result(); + assertFail(r); + assertEquals("Error: Git dependency is not allowed in a library release", r.err.trim()); + } + + { + final r = haxelib(["search", "Foo"]).result(); + // did not get submitted + assertFalse(r.out.indexOf("Foo") >= 0); + } + } + + function testInvalidLicense() { + 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/libInvalidLicense.zip"]), bar.pw]).result(); + assertFail(r); + assertEquals("Error: Invalid value Unknown for License", r.err.trim()); + + final r = haxelib(["search", "Bar"]).result(); + // did not get submitted + assertFalse(r.out.indexOf("Bar") >= 0); + } }