Skip to content
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
Binary file modified run.n
Binary file not shown.
11 changes: 6 additions & 5 deletions src/haxelib/api/Connection.hx
Original file line number Diff line number Diff line change
Expand Up @@ -354,18 +354,19 @@ class Connection {
}

/**
Returns a map of the library names in `libraries` with their validated names
(to ensure correct capitalisation) and available versions.
Returns a map of the library names in `libraries` with their correctly
capitalized names and available versions.
**/
public static function getVersionsForLibraries(libraries:Array<ProjectName>):Map<ProjectName, {confirmedName:ProjectName, versions:Array<SemVer>}> {
public static function getLibraryNamesAndVersions(libraries:Array<ProjectName>):
Map<ProjectName,{confirmedName:ProjectName, versions:Array<SemVer>}>
{
// TODO: can we collapse this into a single API call? It's getting too slow otherwise.
final map = new Map<ProjectName, {confirmedName:ProjectName, versions:Array<SemVer>}>();

for (lib in libraries) {
final info = retry(data.site.infos.bind(lib));
final versionsData = info.versions;
// TODO with stricter capitalisation we won't have to use info.name maybe
map[lib] = {confirmedName: ProjectName.ofString(info.name), versions:[for(data in versionsData) data.name]};
map[lib] = {confirmedName: ProjectName.ofString(info.name), versions: [for (data in versionsData) data.name]};
}
return map;
}
Expand Down
69 changes: 36 additions & 33 deletions src/haxelib/api/Installer.hx
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class UserInterface {
}
}

private class AllInstallData {
private class InstallData {
public final name:ProjectName;
public final version:Version;
public final isLatest:Bool;
Expand All @@ -119,20 +119,20 @@ private class AllInstallData {
this.isLatest = isLatest;
}

public static function create(name:ProjectName, libFlagData:Option<VersionData>, versionData:Null<Array<SemVer>>):AllInstallData {
public static function create(name:ProjectName, libFlagData:Option<VersionData>, versionData:Null<Array<SemVer>>):InstallData {
if (versionData != null && versionData.length == 0)
throw new InstallationException('The library $name has not yet released a version');

return switch libFlagData {
case None:
final semVer = getLatest(versionData);
new AllInstallData(name, semVer, Haxelib(semVer), true);
new InstallData(name, semVer, Haxelib(semVer), true);
case Some(Haxelib(version)) if (!versionData.contains(version)):
throw new InstallationException('No such version $version for library $name');
case Some(Haxelib(version)):
new AllInstallData(name, version, Haxelib(version), version == getLatest(versionData));
new InstallData(name, version, Haxelib(version), version == getLatest(versionData));
case Some(VcsInstall(version, vcsData)):
new AllInstallData(name, version, VcsInstall(version, vcsData), false);
new InstallData(name, version, VcsInstall(version, vcsData), false);
}
}
}
Expand Down Expand Up @@ -253,17 +253,17 @@ class Installer {
// Check the version numbers are all good
userInterface.log("Loading info about the required libraries");

final versionData = getFilteredVersionData(libsToInstall);
final installData = getFilteredInstallData(libsToInstall);

final libVersions = [
for (library in versionData)
for (library in installData)
{name:library.name, version:library.version}
];
// Abort if not confirmed
if (confirmHxmlInstall != null && !confirmHxmlInstall(libVersions))
return;

for (library in versionData) {
for (library in installData) {
if (library.versionData.match(Haxelib(_)) && repository.isVersionInstalled(library.name, library.version)) {
final version = SemVer.ofString(library.version);
if (scope.isLibraryInstalled(library.name) && scope.getVersion(library.name) == version) {
Expand All @@ -279,7 +279,7 @@ class Installer {
}

try
installFromInstallData(library.name, library.versionData)
installFromVersionData(library.name, library.versionData)
catch (e) {
userInterface.log(e.toString());
continue;
Expand Down Expand Up @@ -538,7 +538,7 @@ class Installer {
}

try
installFromInstallData(lib.name, lib.versionData)
installFromVersionData(lib.name, lib.versionData)
catch (e) {
userInterface.log(e.toString());
continue;
Expand Down Expand Up @@ -585,66 +585,69 @@ class Installer {
}
}

static function getInstallData(libs:List<{name:ProjectName, data:Option<VersionData>}>):List<AllInstallData> {
final installData = new List<AllInstallData>();
static function getInstallData(libs:List<{name:ProjectName, data:Option<VersionData>}>):List<InstallData> {
final installData = new List<InstallData>();

final versionsData = getVersionsForEmptyLibs(libs);
final versionsData = getDataForServerLibraries(libs);

for (lib in libs) {
final data = versionsData[lib.name];
if (data == null) {
installData.add(AllInstallData.create(lib.name, lib.data, null));
installData.add(InstallData.create(lib.name, lib.data, null));
continue;
}
final libName = data.confirmedName;
installData.add(AllInstallData.create(libName, lib.data, data.versions));
installData.add(InstallData.create(libName, lib.data, data.versions));
}

return installData;
}

/** Returns a list of all require install data for the `libs`, and also filters out repeated libs. **/
static function getFilteredVersionData(libs:List<{name:ProjectName, data:Option<VersionData>, isTargetLib:Bool}>):List<AllInstallData> {
final installData = new List<AllInstallData>();
/** Returns a list of all required install data for `libs`, and also filters out repeated libs. **/
static function getFilteredInstallData(libs:List<{name:ProjectName, data:Option<VersionData>}>):List<InstallData> {
final installDataList = new List<InstallData>();
final includedLibs = new Map<ProjectName, Array<VersionData>>();

final versionsData = getVersionsForEmptyLibs(libs);
final serverData = getDataForServerLibraries(libs);

for (lib in libs) {
final allInstallData = {
final data = versionsData[lib.name];
final installData = {
final data = serverData[lib.name];
if (data == null) {
AllInstallData.create(lib.name, lib.data, null);
InstallData.create(lib.name, lib.data, null);
} else {
final libName = data.confirmedName;
AllInstallData.create(libName, lib.data, data.versions);
InstallData.create(libName, lib.data, data.versions);
}
}

final lowerCaseName = ProjectName.ofString(allInstallData.name.toLowerCase());
final lowerCaseName = ProjectName.ofString(installData.name.toLowerCase());

final includedVersions = includedLibs[lowerCaseName];
if (includedVersions != null && (lib.isTargetLib || isVersionIncluded(allInstallData.versionData, includedVersions)))
continue; // do not include twice
if (includedVersions == null)
includedLibs[lowerCaseName] = [];
includedLibs[lowerCaseName].push(allInstallData.versionData);
installData.add(allInstallData);
else if (isVersionIncluded(installData.versionData, includedVersions))
continue; // do not include twice
includedLibs[lowerCaseName].push(installData.versionData);
installDataList.add(installData);
}

return installData;
return installDataList;
}

/** Returns a map of version information for libraries in `libs` that have empty version information. **/
static function getVersionsForEmptyLibs(libs:List<{name:ProjectName, data:Option<VersionData>}>):
/**
Returns a map of name and version information for libraries in `libs` that
would be installed from the haxelib server.
**/
static function getDataForServerLibraries(libs:List<{name:ProjectName, data:Option<VersionData>}>):
Map<ProjectName, {confirmedName:ProjectName, versions:Array<SemVer>}>
{
final toCheck:Array<ProjectName> = [];
for (lib in libs)
if (lib.data.match(None | Some(Haxelib(_)))) // Do not check vcs info
toCheck.push(lib.name);

return Connection.getVersionsForLibraries(toCheck);
return Connection.getLibraryNamesAndVersions(toCheck);
}

static function isVersionIncluded(toCheck:VersionData, versions:Array<VersionData>):Bool {
Expand All @@ -666,7 +669,7 @@ class Installer {
return false;
}

function installFromInstallData(library:ProjectName, data:VersionData) {
function installFromVersionData(library:ProjectName, data:VersionData) {
switch data {
case Haxelib(version):
downloadAndInstall(library, version);
Expand Down
31 changes: 25 additions & 6 deletions src/haxelib/api/LibFlagData.hx
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,13 @@ private final libraryFlagEReg = ~/^-(lib|L|-library)\b/;
Extracts the lib information from the hxml file at `path`.

Does not filter out repeated libs.

Target libraries (e.g. hxcpp) are also added if they are not explicitly
included via a -lib flag.
**/
function fromHxml(path:String):List<{name:ProjectName, data:Option<VersionData>, isTargetLib:Bool}> {
final libsData = new List<{name:ProjectName, data:Option<VersionData>, isTargetLib:Bool}>();
function fromHxml(path:String):List<{name:ProjectName, data:Option<VersionData>}> {
final libsData = new List<{name:ProjectName, data:Option<VersionData>}>();
final targetLibraries:Map<ProjectName, Null<Bool>> = [for (_ => lib in TARGETS) lib => null];

final lines = [path];

Expand All @@ -82,8 +86,8 @@ function fromHxml(path:String):List<{name:ProjectName, data:Option<VersionData>,
if (targetFlagEReg.match(line)) {
final target = targetFlagEReg.matched(1);
final lib = TARGETS[target];
if (lib != null)
libsData.add({name: lib, data: None, isTargetLib: true});
if (lib != null && targetLibraries[lib] == null)
targetLibraries[lib] = true;
}

if (libraryFlagEReg.match(line)) {
Expand All @@ -98,10 +102,25 @@ function fromHxml(path:String):List<{name:ProjectName, data:Option<VersionData>,
data: switch (libDataEReg.matched(2)) {
case null: None;
case v: Some(extractVersion(v));
},
isTargetLib: false
}
});
final normalizedName = name.toLowerCase();
if (targetLibraries.exists(normalizedName)) {
// it is included explicitly, so ignore whether the target flag was used
targetLibraries[normalizedName] = false;
}
}
}

// add target libraries required for the hxml that weren't added explicitly
for (targetLib => shouldInstall in targetLibraries) {
if (shouldInstall) {
libsData.add({
name: targetLib,
data: None
});
}
}

return libsData;
}
4 changes: 4 additions & 0 deletions test/libraries/InstallDeps/target-lib-uppercase.hxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-lib HXCPP:git:https://github.com/HaxeFoundation/hxcpp.git

cpp.hxml
# this file contains a --cpp flag
2 changes: 1 addition & 1 deletion test/libraries/InstallDeps/target-lib.hxml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
-lib hxcpp:git:https://github.com/HaxeFoundation/hxcpp.git

other.hxml
cpp.hxml
# this file contains a --cpp flag
20 changes: 15 additions & 5 deletions test/tests/TestInstaller.hx
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,23 @@ class TestInstaller extends TestBase {
}

public function testInstallHxmlWithBackend() {
// inferred from -cpp/--cpp flags
installer.installFromHxml("cpp.hxml", (libs) -> {
assertEquals(1, Lambda.count(libs, (lib) -> lib.name == "hxcpp"));
return false;
});

// specified explicitly
// test for issue #511
installer.installFromHxml("target-lib.hxml", (libs) -> {
var count = 0;
for (lib in libs)
if (lib.name == "hxcpp")
count++;
assertEquals(1, count);
assertEquals(1, Lambda.count(libs, (lib) -> lib.name == "hxcpp"));
return false;
});

// specified explicitly with non-standard capitalisation
installer.installFromHxml("target-lib-uppercase.hxml", (libs) -> {
assertEquals(1, Lambda.count(libs, (lib) -> lib.name == "HXCPP"));
assertEquals(0, Lambda.count(libs, (lib) -> lib.name == "hxcpp"));
return false;
});
}
Expand Down