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

Support Windows paths #33

Merged
merged 33 commits into from
Mar 26, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
cf63763
Base work for portable path
Embraser01 Mar 19, 2019
3ea7ac5
Add conversion where needed (still missing some!)
Embraser01 Mar 20, 2019
ca12605
Got it to work on Windows!
Embraser01 Mar 20, 2019
9d9af0e
Convert to portable path when calling 'yarn <path> install'
Embraser01 Mar 20, 2019
e7f88b3
Update config.ts
arcanis Mar 20, 2019
5afdbfe
Use posix where possible
Embraser01 Mar 20, 2019
9d8c602
Use xfs in json-proxy instead of native fs
Embraser01 Mar 20, 2019
9f7baa7
Fix berry json proxy dependencies
Embraser01 Mar 20, 2019
293d4c4
Handle more special cases (globby, pnp), activate Windows Pipeline
Embraser01 Mar 22, 2019
08434df
Fix PATH env variable when spawn process
Embraser01 Mar 22, 2019
91da8f7
Fix azure yaml
Embraser01 Mar 22, 2019
9e2c73a
Fixes plugin loading
arcanis Mar 22, 2019
a84f28a
Updates the checked-in build
Mar 22, 2019
fd90c88
Fixes yarn-path execution
Mar 22, 2019
15e5a14
Debug: Adds logging to findZip
Mar 22, 2019
1006c08
Revert "Debug: Adds logging to findZip"
Mar 22, 2019
06f4cad
Enforces symlinks on Windows
Mar 22, 2019
935ef94
Fixes the cmd scripts
Mar 22, 2019
47996f1
Adds a retry for EBUSY and ENOTEMPTY
Mar 22, 2019
e5cc92a
Fixes process spawning on win32
arcanis Mar 23, 2019
bff06d3
More portable path, prevent translating to portable path if already one
Embraser01 Mar 24, 2019
c03bdb4
Some cleanup for PnP hook on Windows
Embraser01 Mar 25, 2019
73b0472
Merge branch 'master' into windows-portable-path
Embraser01 Mar 25, 2019
3ea0c94
Use only portable path in Native resolution
Embraser01 Mar 25, 2019
a25e7fd
Moves the portable path conversion in dedicated wrappers
Mar 25, 2019
9b58424
Makes fakeFs a parameter to instantiate a PnP API
Mar 25, 2019
7c49825
Updates the PnP hook
Mar 25, 2019
4633d4f
Fixes accidental infinite loop
Mar 25, 2019
b9d8553
Updates the checked-in PnP hook
Mar 25, 2019
22edde3
Fixes how the PnP linker interacts with the PnP API on Windows
Mar 25, 2019
2891c1a
Implements a fs layer to convert paths before they reach zipopenfs
Mar 25, 2019
010898a
Adds a few extra conversions
arcanis Mar 25, 2019
a9bf0fe
Updates the checked-in build
Mar 25, 2019
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
Prev Previous commit
Next Next commit
Use posix where possible
  • Loading branch information
Embraser01 committed Mar 24, 2019
commit 5afdbfeb09738878696a8f1de5eba56309d45214
2 changes: 1 addition & 1 deletion packages/berry-core/sources/Configuration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ function parseValue(value: unknown, type: SettingsType, folder: string) {
throw new Error(`Expected value to be a string`);

if (type === SettingsType.ABSOLUTE_PATH) {
return posix.resolve(folder, value);
return posix.resolve(folder, NodeFS.toPortablePath(value));
} else if (type === SettingsType.LOCATOR_LOOSE) {
return structUtils.parseLocator(value, false);
} else if (type === SettingsType.LOCATOR) {
Expand Down
140 changes: 70 additions & 70 deletions packages/berry-core/sources/Project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {parseSyml, stringifySyml} from '@berry/parsers';
import {createHmac} from 'crypto';
// @ts-ignore
import Logic from 'logic-solver';
import {dirname, posix} from 'path';
import {posix} from 'path';
// @ts-ignore
import pLimit from 'p-limit';
import semver from 'semver';
Expand Down Expand Up @@ -80,7 +80,7 @@ export class Project {
packageCwd = currentCwd;
}
}
nextCwd = dirname(currentCwd);
nextCwd = posix.dirname(currentCwd);
}

if (!projectCwd || !packageCwd)
Expand Down Expand Up @@ -307,7 +307,7 @@ export class Project {

if (!dependencyMetaSet)
return dependencyMeta;

const defaultMeta = dependencyMetaSet.get(null);
if (defaultMeta)
Object.assign(dependencyMeta, defaultMeta);
Expand Down Expand Up @@ -366,7 +366,7 @@ export class Project {
const fetcher = this.configuration.makeFetcher();

const resolverOptions = {checksums: this.storedChecksums, project: this, cache, fetcher, report, resolver};

const allDescriptors = new Map<DescriptorHash, Descriptor>();
const allPackages = new Map<LocatorHash, Package>();
const allResolutions = new Map<DescriptorHash, LocatorHash>();
Expand Down Expand Up @@ -560,79 +560,79 @@ export class Project {
allDescriptors.set(descriptor.descriptorHash, descriptor);
mustBeResolved.add(descriptor.descriptorHash);

// We must check and make sure that the descriptor didn't get aliased
// to something else
// We must check and make sure that the descriptor didn't get aliased
// to something else
const aliasHash = this.resolutionAliases.get(descriptor.descriptorHash);
if (aliasHash === undefined)
continue;
if (aliasHash === undefined)
continue;

// It doesn't cost us much to support the case where a descriptor is
// equal to its own alias (which should mean "no alias")
if (descriptor.descriptorHash === aliasHash)
continue;
// It doesn't cost us much to support the case where a descriptor is
// equal to its own alias (which should mean "no alias")
if (descriptor.descriptorHash === aliasHash)
continue;

const alias = this.storedDescriptors.get(aliasHash);
if (!alias)
throw new Error(`Assertion failed: The alias should have been registered`);
const alias = this.storedDescriptors.get(aliasHash);
if (!alias)
throw new Error(`Assertion failed: The alias should have been registered`);

// If it's already been "resolved" (in reality it will be the temporary
// resolution we've set in the next few lines) we simply must skip it
if (allResolutions.has(descriptor.descriptorHash))
continue;
// If it's already been "resolved" (in reality it will be the temporary
// resolution we've set in the next few lines) we simply must skip it
if (allResolutions.has(descriptor.descriptorHash))
continue;

// Temporarily set an invalid resolution so that it won't be resolved
// multiple times if it is found multiple times in the dependency
// tree (this is only temporary, we will replace it by the actual
// resolution after we've finished resolving everything)
allResolutions.set(descriptor.descriptorHash, `temporary` as LocatorHash);
// Temporarily set an invalid resolution so that it won't be resolved
// multiple times if it is found multiple times in the dependency
// tree (this is only temporary, we will replace it by the actual
// resolution after we've finished resolving everything)
allResolutions.set(descriptor.descriptorHash, `temporary` as LocatorHash);

// We can now replace the descriptor by its alias in the list of
// descriptors that must be resolved
mustBeResolved.delete(descriptor.descriptorHash);
mustBeResolved.add(aliasHash);
// We can now replace the descriptor by its alias in the list of
// descriptors that must be resolved
mustBeResolved.delete(descriptor.descriptorHash);
mustBeResolved.add(aliasHash);

allDescriptors.set(aliasHash, alias);
allDescriptors.set(aliasHash, alias);

haveBeenAliased.add(descriptor.descriptorHash);
}
}
}

// Each package that should have been resolved but was skipped because it
// was aliased will now see the resolution for its alias propagated to it
// Each package that should have been resolved but was skipped because it
// was aliased will now see the resolution for its alias propagated to it

while (haveBeenAliased.size > 0) {
let hasChanged = false;
while (haveBeenAliased.size > 0) {
let hasChanged = false;

for (const descriptorHash of haveBeenAliased) {
const descriptor = allDescriptors.get(descriptorHash);
if (!descriptor)
throw new Error(`Assertion failed: The descriptor should have been registered`);
for (const descriptorHash of haveBeenAliased) {
const descriptor = allDescriptors.get(descriptorHash);
if (!descriptor)
throw new Error(`Assertion failed: The descriptor should have been registered`);

const aliasHash = this.resolutionAliases.get(descriptorHash);
if (aliasHash === undefined)
throw new Error(`Assertion failed: The descriptor should have an alias`);
const aliasHash = this.resolutionAliases.get(descriptorHash);
if (aliasHash === undefined)
throw new Error(`Assertion failed: The descriptor should have an alias`);

const resolution = allResolutions.get(aliasHash);
if (resolution === undefined)
throw new Error(`Assertion failed: The resolution should have been registered`);
const resolution = allResolutions.get(aliasHash);
if (resolution === undefined)
throw new Error(`Assertion failed: The resolution should have been registered`);

// The following can happen if a package gets aliased to another package
// that's itself aliased - in this case we just process all those we can
// do, then make new passes until everything is resolved
if (resolution === `temporary`)
continue;
// The following can happen if a package gets aliased to another package
// that's itself aliased - in this case we just process all those we can
// do, then make new passes until everything is resolved
if (resolution === `temporary`)
continue;

haveBeenAliased.delete(descriptorHash);
haveBeenAliased.delete(descriptorHash);

allResolutions.set(descriptorHash, resolution);
allResolutions.set(descriptorHash, resolution);

hasChanged = true;
}
hasChanged = true;
}

if (!hasChanged) {
throw new Error(`Alias loop detected`);
}
if (!hasChanged) {
throw new Error(`Alias loop detected`);
}
}

// In this step we now create virtual packages for each package with at
Expand Down Expand Up @@ -846,7 +846,7 @@ export class Project {
const installer = installers.get(linker);
if (!installer)
throw new Error(`Assertion failed: The installer should have been registered`);

const fetchResult = await fetcher.fetch(pkg, fetcherOptions);

let installStatus;
Expand Down Expand Up @@ -878,7 +878,7 @@ export class Project {
const installer = installers.get(packageLinker);
if (!installer)
throw new Error(`Assertion failed: The installer should have been registered`);

const packageLocation = packageLocations.get(pkg.locatorHash);
if (!packageLocation)
throw new Error(`Assertion failed: The package (${structUtils.prettyLocator(this.configuration, pkg)}) should have been registered`);
Expand All @@ -889,22 +889,22 @@ export class Project {
const resolution = this.storedResolutions.get(descriptor.descriptorHash);
if (!resolution)
throw new Error(`Assertion failed: The resolution (${structUtils.prettyDescriptor(this.configuration, descriptor)}) should have been registered`);

const dependency = this.storedPackages.get(resolution);
if (!dependency)
throw new Error(`Assertion failed: The package (${resolution}, resolved from ${structUtils.prettyDescriptor(this.configuration, descriptor)}) should have been registered`);

const dependencyLinker = packageLinkers.get(resolution);
if (!dependencyLinker)
throw new Error(`Assertion failed: The package (${resolution}, resolved from ${structUtils.prettyDescriptor(this.configuration, descriptor)}) should have been registered`);

if (dependencyLinker === packageLinker) {
internalDependencies.push(dependency);
} else {
let externalEntry = externalDependents.get(resolution);
if (!externalEntry)
externalDependents.set(resolution, externalEntry = []);

externalEntry.push(packageLocation);
}
}
Expand All @@ -924,7 +924,7 @@ export class Project {
const installer = installers.get(packageLinker);
if (!installer)
throw new Error(`Assertion failed: The installer should have been registered`);

await installer.attachExternalDependents(pkg, dependentPaths);
}

Expand All @@ -940,16 +940,16 @@ export class Project {

for (const locatorHash of buildablePackages)
readyPackages.delete(locatorHash);

// We'll use this function is order to compute a hash for each package
// that exposes a build directive. If the hash changes compared to the
// previous run, the package is rebuilt. This has the advantage of making
// the rebuilds much more predictable than before, and to give us the tools
// later to improve this further by explaining *why* a rebuild happened.

const getBuildHash = (locator: Locator) => {
const hash = createHmac(`sha512`, `berry`);

const traverse = (locatorHash: LocatorHash, seenPackages: Set<string> = new Set()) => {
hash.update(locatorHash);

Expand Down Expand Up @@ -990,13 +990,13 @@ export class Project {
const pkg = this.storedPackages.get(locatorHash);
if (!pkg)
throw new Error(`Assertion failed: The package should have been registered`);

let isBuildable = true;
for (const dependency of pkg.dependencies.values()) {
const resolution = this.storedResolutions.get(dependency.descriptorHash);
if (!resolution)
throw new Error(`Assertion failed: The resolution (${structUtils.prettyDescriptor(this.configuration, dependency)}) should have been registered`);

if (buildablePackages.has(resolution)) {
isBuildable = false;
break;
Expand All @@ -1007,7 +1007,7 @@ export class Project {
// before trying to build it (since it might need them to build itself)
if (!isBuildable)
continue;

buildablePackages.delete(locatorHash);

const buildHash = getBuildHash(pkg);
Expand All @@ -1020,7 +1020,7 @@ export class Project {
report.reportInfo(MessageName.MUST_REBUILD, `${structUtils.prettyLocator(this.configuration, pkg)} must be rebuilt because its dependency tree changed`);
else
report.reportInfo(MessageName.MUST_BUILD, `${structUtils.prettyLocator(this.configuration, pkg)} must be built because it never did before or the last one failed`);

const buildDirective = packageBuildDirectives.get(pkg.locatorHash);
if (!buildDirective)
throw new Error(`Assertion failed: The build directive should have been registered`);
Expand Down Expand Up @@ -1064,7 +1064,7 @@ export class Project {
const pkg = this.storedPackages.get(locatorHash);
if (!pkg)
throw new Error(`Assertion failed: The package should have been registered`);

return structUtils.prettyLocator(this.configuration, pkg);
}).join(`, `);

Expand Down
8 changes: 4 additions & 4 deletions packages/berry-core/sources/VirtualFetcher.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AliasFS, xfs} from '@berry/fslib';
import {dirname, relative, resolve} from 'path';
import {posix} from 'path';

import {Fetcher, FetchOptions, FetchResult, MinimalFetchOptions} from './Fetcher';
import * as structUtils from './structUtils';
Expand Down Expand Up @@ -45,17 +45,17 @@ export class VirtualFetcher implements Fetcher {

getLocatorPath(locator: Locator, opts: MinimalFetchOptions) {
const virtualFolder = opts.project.configuration.get(`virtualFolder`);
const virtualPath = resolve(virtualFolder, this.getLocatorFilename(locator));
const virtualPath = posix.resolve(virtualFolder, this.getLocatorFilename(locator));

return virtualPath;
}

private async ensureVirtualLink(locator: Locator, sourceFetch: FetchResult, opts: FetchOptions) {
const virtualPath = this.getLocatorPath(locator, opts);
const relativeTarget = relative(dirname(virtualPath), sourceFetch.packageFs.getRealPath());
const relativeTarget = posix.relative(posix.dirname(virtualPath), sourceFetch.packageFs.getRealPath());

// Doesn't need locking, and the folder must exist for the lock to succeed
await xfs.mkdirpPromise(dirname(virtualPath));
await xfs.mkdirpPromise(posix.dirname(virtualPath));

await xfs.lockPromise(virtualPath, async () => {
let currentLink;
Expand Down
4 changes: 4 additions & 0 deletions packages/berry-fslib/sources/NodeFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ export class NodeFS extends FakeFS {
// And transform to "/mnt/n/berry/scripts/plugin-pack.js"

const {root} = win32.parse(p);

// If relative path, just replace win32 slashes by posix slashes
if (!root) return p.replace(/\\/g, '/');

const driveLetter = root[0].toLowerCase();
const pathWithoutRoot = p.substr(root.length);
const posixPath = pathWithoutRoot.replace(/\\/g, '/');
Expand Down
2 changes: 1 addition & 1 deletion packages/berry-fslib/sources/ZipFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export class ZipFS extends FakeFS {
if (readOnly)
flags |= libzip.ZIP_RDONLY;

this.zip = libzip.open(p, flags, errPtr);
this.zip = libzip.open(NodeFS.fromPortablePath(p), flags, errPtr);

if (this.zip === 0) {
const error = libzip.struct.errorS();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {Configuration, PluginConfiguration, Project} from '@berry/core';
import {httpUtils} from '@berry/core';
import {xfs} from '@berry/fslib';
import Joi from 'joi';
import {dirname, resolve} from 'path';
import {posix} from 'path';
import semver, {SemVer} from 'semver';
import {Readable, Writable} from 'stream';

Expand Down Expand Up @@ -166,10 +166,10 @@ export default (concierge: any, pluginConfiguration: PluginConfiguration) => con
const bundle = await httpUtils.get(bundleUrl, configuration);

const executablePath = `.berry/releases/berry-${bundleVersion}.js`;
const absoluteExecutablePath = resolve(project.cwd, executablePath);
const absoluteExecutablePath = posix.resolve(project.cwd, executablePath);

stdout.write(`Saving it into ${configuration.format(executablePath, `magenta`)}...\n`);
await xfs.mkdirpPromise(dirname(absoluteExecutablePath));
await xfs.mkdirpPromise(posix.dirname(absoluteExecutablePath));
await xfs.writeFilePromise(absoluteExecutablePath, bundle);
await xfs.chmodPromise(absoluteExecutablePath, 0o755);

Expand Down
4 changes: 2 additions & 2 deletions packages/plugin-init/sources/commands/init.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import {structUtils} from '@berry/core';
import {xfs} from '@berry/fslib';
import {updateAndSave} from '@berry/json-proxy';
import {UsageError} from '@manaflair/concierge';
import {basename} from 'path';
import {posix} from 'path';

export default (concierge: any, pluginConfiguration: PluginConfiguration) => concierge

Expand Down Expand Up @@ -42,7 +42,7 @@ export default (concierge: any, pluginConfiguration: PluginConfiguration) => con
const configuration = await Configuration.find(cwd, pluginConfiguration);

const manifest = new Manifest();
manifest.name = structUtils.makeIdent(configuration.get(`initScope`), basename(cwd));
manifest.name = structUtils.makeIdent(configuration.get(`initScope`), posix.basename(cwd));
manifest.version = configuration.get(`initVersion`);
manifest.private = notPublic;
manifest.license = configuration.get(`initLicense`);
Expand Down
4 changes: 2 additions & 2 deletions packages/vscode-zipfs/sources/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {basename} from 'path';
import {posix} from 'path';
import * as vscode from 'vscode';

import {ZipFSProvider} from './ZipFSProvider';
Expand All @@ -8,7 +8,7 @@ function mount(uri: vscode.Uri) {

if (vscode.workspace.getWorkspaceFolder(zipUri) === undefined) {
vscode.workspace.updateWorkspaceFolders(vscode.workspace.workspaceFolders!.length, 0, {
name: basename(zipUri.path),
name: posix.basename(zipUri.path),
uri: zipUri,
});
}
Expand Down