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

Feature/msi filetype #75

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,4 @@ node_modules
.env

docs/_book/
.idea/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really required?

2 changes: 1 addition & 1 deletion docs/assets.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Filetype and usage will be detected from the extension:

| Platform | Extensions (sorted by priority) |
| -------- | ---------- |
| Windows | `.exe`, `.nupkg`, `.zip` |
| Windows | `.exe`, `.nupkg`, `.zip`, `.msi` |
| OS X | `.dmg`, `.zip` |
| Linux | `.deb`, `.rpm`, `.zip` |

Expand Down
2 changes: 1 addition & 1 deletion docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Since version 3.0.0, Nuts can works with [other backends](https://github.com/Git

Nuts can detect the type of file from its filename, there is no strict policy on file naming. Nuts tries to respect the filename/extension conventions for the different platforms. request:)

- Windows: `.exe`, `.nupkg` etc
- Windows: `.exe`, `.nupkg`, `.msi` etc
- Linux: `.deb`, `.tar.gz`, etc
- OS X: `.dmg`, etc

Expand Down
1 change: 1 addition & 0 deletions docs/using-it.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ Using Nuts for your application? Post a Pull-Request!

- [GitBook Editor](https://www.gitbook.com/editor)
- [DeckHub](https://getdeckhub.com)
- [c2softwareDesk] (http://desktop.c2software.de)

4 changes: 2 additions & 2 deletions lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ module.exports = {
},

'versions': function (req) {
return this.versions.filter({
return this.versions.select({
platform: req.query.platform,
channel: req.query.channel || '*'
channel: req.query.channel
});
},

Expand Down
25 changes: 13 additions & 12 deletions lib/nuts.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Nuts.prototype._init = function() {
if (!that.opts.preFetch) return
return that.versions.list();
});
}
};


// Perform a hook using promised functions
Expand All @@ -107,7 +107,7 @@ Nuts.prototype.performQ = function(name, arg, fn) {
.then(function() {
next();
}, next);
})
});
};

// Serve an asset to the response
Expand Down Expand Up @@ -211,6 +211,7 @@ Nuts.prototype.onUpdate = function(req, res, next) {
var fullUrl = getFullUrl(req);
var platform = req.params.platform;
var tag = req.params.version;
var channel = req.query.channel;
var filetype = req.query.filetype ? req.query.filetype : "zip";

Q()
Expand All @@ -220,10 +221,10 @@ Nuts.prototype.onUpdate = function(req, res, next) {

platform = platforms.detect(platform);

return that.versions.filter({
tag: '>='+tag,
return that.versions.newer({
tag: tag,
platform: platform,
channel: '*'
channel: channel
});
})
.then(function(versions) {
Expand Down Expand Up @@ -255,15 +256,16 @@ Nuts.prototype.onUpdateWin = function(req, res, next) {
var fullUrl = getFullUrl(req);
var platform = 'win_32';
var tag = req.params.version;
var channel = req.query.channel;

that.init()
.then(function() {
platform = platforms.detect(platform);

return that.versions.filter({
tag: '>='+tag,
return that.versions.newer({
tag: tag,
platform: platform,
channel: '*'
channel: channel
});
})
.then(function(versions) {
Expand All @@ -285,7 +287,7 @@ Nuts.prototype.onUpdateWin = function(req, res, next) {

// Change filename to use download proxy
.map(function(entry) {
entry.filename = urljoin(fullUrl, '/../../../../', '/download/'+entry.semver+'/'+entry.filename);
entry.filename = urljoin(fullUrl, '/../../../../', '/download/'+entry.version+'/'+entry.filename);

return entry;
})
Expand All @@ -309,9 +311,8 @@ Nuts.prototype.onServeNotes = function(req, res, next) {

Q()
.then(function() {
return that.versions.filter({
tag: tag? '>='+tag : '*',
channel: '*'
return that.versions.select({
tag: tag
});
})
.then(function(versions) {
Expand Down
5 changes: 3 additions & 2 deletions lib/utils/platforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ function detectPlatform(platform) {

// Detect prefix: osx, widnows or linux
if (_.contains(name, 'win')
|| hasSuffix(name, '.exe')) prefix = platforms.WINDOWS;
|| hasSuffix(name, '.exe')
|| hasSuffix(name, '.msi')) prefix = platforms.WINDOWS;

if (_.contains(name, 'linux')
|| _.contains(name, 'ubuntu')
Expand Down Expand Up @@ -72,7 +73,7 @@ function satisfiesPlatform(platform, list) {
function resolveForVersion(version, platformID, opts) {
opts = _.defaults(opts || {}, {
// Order for filetype
filePreference: ['.exe', '.dmg', '.deb', '.rpm', '.tgz', '.tar.gz', '.zip', '.nupkg'],
filePreference: ['.exe', '.msi', '.dmg', '.deb', '.rpm', '.tgz', '.tar.gz', '.zip', '.nupkg'],
wanted: null
});

Expand Down
24 changes: 18 additions & 6 deletions lib/utils/win-releases.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ var CHANNELS = [

// RELEASES parsing
var releaseRe = /^([0-9a-fA-F]{40})\s+(\S+)\s+(\d+)[\r]*$/;
var suffixRe = /(-full|-delta)?\.nupkg/;
var versionRe = /\d+(\.\d+){0,3}(-[a-z][0-9a-z-\.]*$)?$/;
var prereleaseRe = /-[a-z][0-9a-z-\.]*$/;


// Hash a prerelease
Expand Down Expand Up @@ -73,13 +76,22 @@ function parseRELEASES(content) {
.split(/\.|-/)
.reverse();

var version = _.chain(filenameParts)
.filter(function(x) {
return /^\d+$/.exec(x);
var version = _.chain(
filename
.replace(suffixRe, '')
.match(versionRe)
)
.thru(function(matchResult) {
return matchResult ? matchResult[0] : '';
})
.reverse()
.value()
.join('.');
.replace(prereleaseRe, function(prerelease) {
// NuGet doesn't support dots in prereleases
// https://docs.nuget.org/create/versioning#user-content-prerelease-versions
return prerelease.replace(/\./g, '');
})
.value();

if (!version) throw new Error('Release missing valid version: ' + filename);

return {
sha: parts[1],
Expand Down
83 changes: 63 additions & 20 deletions lib/versions.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ var semver = require('semver');

var platforms = require('./utils/platforms');

var channelRe = /^[a-z]*/;

// Normalize tag name
function normalizeTag(tag) {
if (tag[0] == 'v') tag = tag.slice(1);
Expand All @@ -15,7 +17,7 @@ function extractChannel(tag) {
var suffix = tag.split('-')[1];
if (!suffix) return 'stable';

return suffix.split('.')[0];
return suffix.match(channelRe)[0] || suffix.split('.')[0];
}

// Normalize a release to a version
Expand All @@ -36,6 +38,8 @@ function normalizeVersion(release) {
filename: asset.name,
size: asset.size,
content_type: asset.content_type,
download_url: asset.url,
download_count: asset.download_count,
raw: asset
};
})
Expand All @@ -47,7 +51,8 @@ function normalizeVersion(release) {
channel: extractChannel(release.tag_name),
notes: release.body || "",
published_at: new Date(release.published_at),
platforms: releasePlatforms
platforms: releasePlatforms,
download_count: downloadCount
};
}

Expand All @@ -62,6 +67,45 @@ function compareVersions(v1, v2) {
return 0;
}

function supportsPlatform(requestedPlatform, versionPlatforms) {
return (!requestedPlatform ||
platforms.satisfies(requestedPlatform, _.pluck(versionPlatforms, 'type')));
}

function matchingChannel(requestedChannel, versionChannel) {
return (!requestedChannel ||
requestedChannel === '*' ||
versionChannel === requestedChannel);
}

// Creates filter function that checks for updates
function newVersionFilter(opts) {
return function(version) {
// Not available for requested paltform
if (!supportsPlatform(opts.platform, version.platforms)) {
return false;
}

// If the caller specifies a channel then stay on that channel. Otherwise
// look for anything closer to the main release.
if (opts.channel) {
return (opts.channel === version.channel &&
semver.rcompare(version.tag, opts.tag) <= 0);
} else {
return semver.satisfies(version.tag, '>=' + opts.tag);
}
}
}

// Creates generic filter function for all versions
function allVersionFilter(opts) {
return function(version) {
return ((!opts.tag || opts.tag === version.tag) &&
matchingChannel(opts.channel, version.channel) &&
supportsPlatform(opts.platform, version.platforms));
}
}

function Versions(backend) {
this.backend = backend;

Expand All @@ -87,34 +131,33 @@ Versions.prototype.get = function(tag) {
};

// Filter versions with criterias
Versions.prototype.filter = function(opts) {
opts = _.defaults(opts || {}, {
tag: 'latest',
platform: null,
channel: 'stable'
});
Versions.prototype.filter = function(opts, filterBuilder) {
opts = opts || {};
if (opts.platform) opts.platform = platforms.detect(opts.platform);

return this.list()
.then(function(versions) {
return _.chain(versions)
.filter(function(version) {
// Check channel
if (opts.channel != '*' && version.channel != opts.channel) return false;

// Not available for requested paltform
if (opts.platform && !platforms.satisfies(opts.platform, _.pluck(version.platforms, 'type'))) return false;

// Check tag satisfies request version
return opts.tag == 'latest' || semver.satisfies(version.tag, opts.tag);
})
.filter(filterBuilder(opts))
.value();
});
};

Versions.prototype.newer = function (opts) {
return this.filter(opts, newVersionFilter);
};

Versions.prototype.select = function (opts) {
return this.filter(opts, allVersionFilter);
};

// Resolve a platform, by filtering then taking the first result
Versions.prototype.resolve = function(opts) {
return this.filter(opts)
opts = opts || {};
opts.channel = opts.channel || 'stable';
if (opts.tag === 'latest') opts.tag = null;

return this.filter(opts, allVersionFilter)
.then(function(versions) {
var version = _.first(versions);
if (!version) throw new Error('Version not found: '+opts.tag);
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
},
"devDependencies": {
"mocha": "1.18.2",
"mockery": "^1.4.0",
"rewire": "^2.5.1",
"should": "7.0.4"
},
"bugs": {
Expand Down
15 changes: 14 additions & 1 deletion test/platforms.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ describe('Platforms', function() {
it('should detect windows_32', function() {
platforms.detect('myapp-v0.25.1-win32-ia32.zip').should.be.exactly(platforms.WINDOWS_32);
platforms.detect('atom-1.0.9-delta.nupkg').should.be.exactly(platforms.WINDOWS_32);
platforms.detect('TestSetup.msi').should.be.exactly(platforms.WINDOWS_32);
platforms.detect('RELEASES').should.be.exactly(platforms.WINDOWS_32);
});

Expand Down Expand Up @@ -78,6 +79,14 @@ describe('Platforms', function() {
"content_type": "application/zip",
"download_url": "https://api.github.com/repos/atom/atom/releases/assets/825728",
"download_count": 5612
},
{
"type": "windows_32",
"filename": "TestSetup.msi",
"size": 78675700,
"content_type": "application/x-msi",
"download_url": "https://api.github.com/repos/test/test2/releases/assets/7938398",
"download_count": 1
}
]
};
Expand All @@ -91,7 +100,11 @@ describe('Platforms', function() {
it('should resolve to best platform with a preferred filetype', function() {
platforms.resolve(version, 'osx', {
filePreference: ['.zip']
}).filename.should.be.exactly("test-3.3.1-darwin-x64.zip")
}).filename.should.be.exactly("test-3.3.1-darwin-x64.zip"),

platforms.resolve(version, 'win32', {
filePreference: ['.msi']
}).filename.should.be.exactly("TestSetup.msi")
});

it('should resolve to best platform with a wanted filetype', function() {
Expand Down
Loading