Skip to content

Commit

Permalink
Merged release/1.5.0 into master
Browse files Browse the repository at this point in the history
  • Loading branch information
heikomat committed Jan 29, 2017
2 parents 65e15ef + d64780c commit ceb0e85
Show file tree
Hide file tree
Showing 9 changed files with 181 additions and 65 deletions.
17 changes: 0 additions & 17 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -1,20 +1,3 @@
Skip to content
This repository
Search
Pull requests
Issues
Gist
@heikomat
Unwatch 16
Star 0
Fork 0 5minds/5minds.kaizen Private
Code Issues 50 Pull requests 0 Projects 1 Wiki Pulse Graphs
Branch: develop Find file Copy path5minds.kaizen/backend/.editorconfig
1a1bedf on 8 Sep
@heikomat heikomat Move main modules to parent-folder
1 contributor
RawBlameHistory
17 lines (12 sloc) 258 Bytes
# EditorConfig is awesome: http://EditorConfig.org

root = true
Expand Down
5 changes: 4 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
{
"extends": "5minds"
"extends": "5minds",
"rules": {
"object-shorthand":"off"
}
}
71 changes: 71 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# 1.5.0
### New Features
- Support for local modules as dependencies in other local modules.
aka. if your local module A requires your local module B, B wont be downloaded, but linked, if the local version of B matches A's dependency
- Minstall now allows `.` as module-folder
for when you just want to install and link a bunch of modules, that don't have a parent-project (this is experimental, please open an issue if this feature leads to problems)

### Bugfixes
- Fix handling of scoped local modules
- local scoped modules are now linked using their scoped-names, no matter what the folder they are actually in is called

### Improvements
- Updated the version of fs-extra minstall uses to 2.0.0
- some code cleanup

# 1.4.0
### Bugfixes
- Fix installing a package as dependency with minstall-postinstall (see #16)

# 1.3.7
### Bugfixes
- Fix already linked modules from a previous installation not being deleted before reinstall

### Improvements
- Add stdout-log to output when a command from within minstall fails

# 1.3.6
### Bugfixes
- Fix installing of conflicting scoped dependencies

# 1.3.3
### Bugfixes
- Fix wrong module-folder usage

# 1.3.2
### Improvements
- Greatly improve logs. npm-warnings are now silenced (errors are still shown though)

# 1.3.1
### New Features
- **minstall now installs conflicting dependencies correctly**, but gives a hint that the user might try to use non-conflicting package-versions
- minstall now better detects, when it's started from the wrong folder, and exits without doing anything

### Bugfixes
- through the use of fs-extra instead of fs, the filesystem-operations are now easier and less prone to error

### Improvements
- Code cleanup

# 1.2.0
### Improvements
- minstall will now throw an error and exit, if it detects incompatible versions of the same dependency
- Code cleanup
- use of the 5minds-eslint-styleguides instead of these from airbnb

# 1.1.0
### Improvements
- Module-installation (especially for large projects) is now a lot faster
- Running the script in a project-folder, that is already installed is now a lot faster
- The whole code got refactored and cleaned up
- Some logs are a little nicer

# 1.0.8
### New Features
- added `modules-folder`-argument

### Bugfixes
- when verifying folder names, a non-existing folder is now considered unverified, instead of throwing an error

### Improvements
- Messages, for when there is nothing to do for minstall look like nice exit-messages now, instead of like errors
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@ my-modular-app
```

## In collaboration with

![5Minds IT-Solutions](img/5minds_logo.png "5Minds IT-Solutions")

#### [5minds.de](https://5minds.de)

#### [github.com/5minds](https://github.com/5minds)
9 changes: 9 additions & 0 deletions lib/ModuleInfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class ModuleInfo {

constructor(folderName, name, version, dependencies, postinstall) {
this._folderName = folderName;
this._realFolderName = folderName;
this._name = name;
this._version = version;
this._dependencies = dependencies;
Expand All @@ -18,10 +19,18 @@ class ModuleInfo {
}
}

// gets the folder-name the module should have according to it's module-name
get folderName() {
return this._folderName;
}

// get's the folder-name the module actually has on the disk.
// This should only differ from folderName for local modules,
// never for modules within node_modules
get realFolderName() {
return this._realFolderName;
}

get name() {
return this._name;
}
Expand Down
108 changes: 77 additions & 31 deletions lib/minstall.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const os = require('os');
const path = require('path');
const Promise = require('bluebird');
const readline = require('readline');

const cwd = process.cwd();

const UncriticalError = require('./UncriticalError.js');
Expand Down Expand Up @@ -59,6 +60,9 @@ function checkStartConditions() {
}
}

if (moduletools.modulesFolder === '.') {
return Promise.resolve('.');
}
return systools.verifyFolderName(cwd, moduletools.modulesFolder);
})
.then((folderName) => {
Expand All @@ -67,7 +71,7 @@ function checkStartConditions() {
}

if (installedAsDependency) {
return;
return null;
}

return Promise.all([
Expand All @@ -91,10 +95,15 @@ function checkStartConditions() {
});
}

function linkModuleToRoot(moduleFolder) {
const targetPath = path.join(cwd, 'node_modules', moduleFolder);
const modulePath = path.join(cwd, moduletools.modulesFolder, moduleFolder);
return systools.link(modulePath, targetPath);
function linkModulesToRoot(moduleInfos) {
return Promise.all(moduleInfos.map((moduleInfo) => {

// local modules should be linked using the folder-names they should have,
// no matter what folder-name they actually have, therefore don't use .realFolderName here
const targetPath = path.join(cwd, 'node_modules', moduleInfo.folderName);
const modulePath = path.join(cwd, moduletools.modulesFolder, moduleInfo.realFolderName);
return systools.link(modulePath, targetPath);
}));
}

function linkRootToModule(moduleFolder) {
Expand All @@ -116,8 +125,8 @@ function runPostinstall(moduleInfo) {
return Promise.resolve();
}

const modulePath = path.join(cwd, moduletools.modulesFolder, moduleInfo.folderName);
return linkRootToModule(moduleInfo.folderName)
const modulePath = path.join(cwd, moduletools.modulesFolder, moduleInfo.realFolderName);
return linkRootToModule(moduleInfo.realFolderName)
.then(() => {

let command = moduleInfo.postinstall;
Expand All @@ -132,40 +141,61 @@ function runPostinstall(moduleInfo) {
});
}

function cacheConflictingModules(conflictedDependencies, moduleFolderName) {
function cacheConflictingModules(conflictedDependencies, localModules, moduleFolderName) {

if (conflictedDependencies.length === 0) {
return Promise.resolve();
return Promise.resolve([]);
}

const conflictedDependencyFolders = conflictedDependencies.map((dependency) => {
const localModuleNames = localModules.map((module) => {
return module.name;
});

// local modules are linked at the very end of the installation, thus all
// local modules are "not yet linked"
const cachedModuleFolders = conflictedDependencies.filter((module) => {
return localModuleNames.indexOf(module.name) < 0;
})
.map((dependency) => {
return dependency.folderName;
});

if (cachedModuleFolders.length === 0) {
return Promise.resolve([]);
}

const rootNodeModules = path.join(cwd, 'node_modules');
const cacheFolder = path.join(rootNodeModules, `${moduleFolderName}_cache`);
return systools.moveMultiple(conflictedDependencyFolders, rootNodeModules, cacheFolder);
return systools.moveMultiple(cachedModuleFolders, rootNodeModules, cacheFolder)
.then(() => {
return cachedModuleFolders;
});
}

function uncacheConflictingModules(conflictedDependencies, moduleFolderName) {
function uncacheConflictingModules(cachedModuleFolders, conflictingModules, moduleFolderName) {

if (conflictedDependencies.length === 0) {
if (cachedModuleFolders.length === 0 && conflictingModules.length === 0) {
return Promise.resolve();
}

const conflictedDependencyFolders = conflictedDependencies.map((dependency) => {
return dependency.folderName;
const conflictingModuleFolders = conflictingModules.map((module) => {
// the conflicting packet was installed into the folderName that it's module-name
// requires it to have, thus don't use the realFolderName from the conflicting module
// as this might be a local name, that is not the same
return module.folderName;
});

const rootNodeModules = path.join(cwd, 'node_modules');
const cacheFolder = path.join(rootNodeModules, `${moduleFolderName}_cache`);
const moduleFolder = path.join(cwd, moduletools.modulesFolder, moduleFolderName);
const moduleNodeModules = path.join(moduleFolder, 'node_modules');

return systools.moveMultiple(conflictedDependencyFolders, rootNodeModules, moduleNodeModules)
// because of possible local modules, the conflicting modules and the actually cached modules don't have to be the same
// move all modules that caused conflicts to the module-node_modules, but only uncache the modules that actually got cached
return systools.moveMultiple(conflictingModuleFolders, rootNodeModules, moduleNodeModules)
.then(() => {

return systools.moveMultiple(conflictedDependencyFolders, cacheFolder, rootNodeModules);
return systools.moveMultiple(cachedModuleFolders, cacheFolder, rootNodeModules);
})
.then(() => {

Expand Down Expand Up @@ -202,35 +232,34 @@ function installModules(installedModules, moduleInfos, index) {
if (moduleInfos.length > 9 && moduleNumber <= 9) {
moduleNumber = `0${moduleNumber}`;
}
process.stdout.write(`installing module ${moduleNumber}/${moduleInfos.length} -> ${moduleInfo.folderName} `);
process.stdout.write(`installing module ${moduleNumber}/${moduleInfos.length} -> ${moduleInfo.realFolderName} `);
}

let packetsToKeep;
const deps = moduletools.getModuleDependencies(installedModules, moduleInfo);
let cachedModuleFolders;
const deps = moduletools.getModuleDependencies(installedModules, moduleInfos, moduleInfo);
if (deps.messages.length > 0) {
logVersionConflict(deps.messages, moduleInfo.folderName);
logVersionConflict(deps.messages, moduleInfo.realFolderName);
}

return moduletools.getPreinstalledPacketsEvaluation(moduleInfo.folderName, deps.missing)
return moduletools.getPreinstalledPacketsEvaluation(moduleInfo.realFolderName, deps.missing)
.then((result) => {
packetsToKeep = result.keep;
deps.missing = result.missing;
return cacheConflictingModules(deps.conflicted, moduleInfo.folderName);
return cacheConflictingModules(deps.conflicted, moduleInfos, moduleInfo.realFolderName);
})
.then(() => {
return persistExistingConfilctingDependencies(packetsToKeep, moduleInfo.folderName);
.then((newlyCachedModuleFolders) => {
cachedModuleFolders = newlyCachedModuleFolders;
return persistExistingConfilctingDependencies(packetsToKeep, moduleInfo.realFolderName);
})
.then(() => {
return installMissingModuleDependencies(moduleInfo.folderName, deps.missing);
return installMissingModuleDependencies(moduleInfo.realFolderName, deps.missing);
})
.then(() => {
return runPostinstall(moduleInfo);
})
.then(() => {
return uncacheConflictingModules(deps.conflicted, moduleInfo.folderName);
})
.then(() => {
return linkModuleToRoot(moduleInfo.folderName);
return uncacheConflictingModules(cachedModuleFolders, deps.conflicted, moduleInfo.realFolderName);
})
.then(() => {
return getInstalledModules();
Expand All @@ -254,7 +283,7 @@ function prepareInstallAsDependency() {
dependencyInstallLinkedFolders.splice(dependencyInstallLinkedFolders.indexOf(projectFolderName), 1);

return Promise.all(dependencyInstallLinkedFolders.map((folderName) => {
systools.link(path.join(cwd, '..', folderName), path.join(cwd, 'node_modules', folderName))
systools.link(path.join(cwd, '..', folderName), path.join(cwd, 'node_modules', folderName));
}));
});
}
Expand All @@ -269,7 +298,7 @@ function cleanupInstallAsDependency() {
return systools.getFolderNames(path.join(cwd, 'node_modules'));
})
.then((folderNames) => {
return systools.moveMultiple(folderNames, path.join(cwd, 'node_modules'), path.join(cwd, '..'))
return systools.moveMultiple(folderNames, path.join(cwd, 'node_modules'), path.join(cwd, '..'));
})
.then(() => {
return systools.delete(path.join(cwd, 'node_modules'));
Expand Down Expand Up @@ -309,6 +338,18 @@ function run() {
.then((modules) => {
installedModules = modules[0];
moduleInfos = modules[1];
moduleInfos.sort((module1, module2) => {
if (Object.keys(module1.dependencies).indexOf(module2.name) >= 0) {
return 1;
}

if (Object.keys(module2.dependencies).indexOf(module1.name) >= 0) {
return -1;
}

return 0;
});

if (moduleInfos.length === 0) {
throw new UncriticalError('no modules found, thus minstall is done :)');
}
Expand All @@ -319,12 +360,17 @@ function run() {
}
logIfInRoot(`minstall found ${moduleInfos.length} local ${moduleText} in '${moduletools.modulesFolder}'`);
return Promise.all(moduleInfos.map((moduleInfo) => {
// local modules should be linked using the folder-names they should have,
// no matter what folder-name they actually have, therefore don't use .realFolderName here
return systools.delete(path.join(cwd, 'node_modules', moduleInfo.folderName));
}));
})
.then(() => {
return installModules(installedModules, moduleInfos);
})
.then(() => {
return linkModulesToRoot(moduleInfos);
})
.then(() => {
return cleanupInstallAsDependency();
})
Expand Down
Loading

0 comments on commit ceb0e85

Please sign in to comment.