Skip to content

Commit e05b542

Browse files
committed
Add extra directory when linking scoped package
1 parent 01f6e04 commit e05b542

File tree

4 files changed

+60
-16
lines changed

4 files changed

+60
-16
lines changed

crates/volta-core/src/run/executor.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -237,6 +237,23 @@ impl PackageInstallCommand {
237237
})
238238
}
239239

240+
pub fn for_npm_link<A, S>(args: A, platform: Platform, name: String) -> Fallible<Self>
241+
where
242+
A: IntoIterator<Item = S>,
243+
S: AsRef<OsStr>,
244+
{
245+
let installer = DirectInstall::with_name(PackageManager::Npm, name)?;
246+
247+
let mut command = create_command("npm");
248+
command.args(args);
249+
250+
Ok(PackageInstallCommand {
251+
command,
252+
installer,
253+
platform,
254+
})
255+
}
256+
240257
/// Adds or updates environment variables that the command will use
241258
pub fn envs<E, K, V>(&mut self, envs: E)
242259
where

crates/volta-core/src/run/npm.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub(super) fn command(args: &[OsString], session: &mut Session) -> Fallible<Exec
3535
CommandArg::Intercepted(InterceptedCommand::Link(link)) => {
3636
// For link commands, only intercept if a platform exists
3737
if let Some(platform) = Platform::current(session)? {
38-
return link.executor(platform);
38+
return link.executor(platform, current_project_name(session));
3939
}
4040
}
4141
CommandArg::Intercepted(InterceptedCommand::Unlink) => {

crates/volta-core/src/run/parser.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -345,12 +345,15 @@ pub struct LinkArgs<'a> {
345345
}
346346

347347
impl<'a> LinkArgs<'a> {
348-
pub fn executor(self, platform: Platform) -> Fallible<Executor> {
348+
pub fn executor(self, platform: Platform, project_name: Option<String>) -> Fallible<Executor> {
349349
if self.tools.is_empty() {
350350
// If no tools are specified, then this is a bare link command, linking the current
351351
// project as a global package. We treat this exactly like a global install
352-
PackageInstallCommand::new(self.common_args, platform, PackageManager::Npm)
353-
.map(Into::into)
352+
match project_name {
353+
Some(name) => PackageInstallCommand::for_npm_link(self.common_args, platform, name),
354+
None => PackageInstallCommand::new(self.common_args, platform, PackageManager::Npm),
355+
}
356+
.map(Into::into)
354357
} else {
355358
// If there are tools specified, then this represents a command to link a global
356359
// package into the current project. We handle each tool separately to support Volta's

crates/volta-core/src/tool/package/mod.rs

Lines changed: 36 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ pub struct Package {
3535

3636
impl Package {
3737
pub fn new(name: String, version: VersionSpec) -> Fallible<Self> {
38-
let staging = setup_staging_directory(PackageManager::Npm)?;
38+
let staging = setup_staging_directory(PackageManager::Npm, false /* needs_scope */)?;
3939

4040
Ok(Package {
4141
name,
@@ -126,13 +126,28 @@ impl Display for Package {
126126
pub struct DirectInstall {
127127
staging: TempDir,
128128
manager: PackageManager,
129+
name: Option<String>,
129130
}
130131

131132
impl DirectInstall {
132133
pub fn new(manager: PackageManager) -> Fallible<Self> {
133-
let staging = setup_staging_directory(manager)?;
134+
let staging = setup_staging_directory(manager, false /* needs_scope */)?;
134135

135-
Ok(DirectInstall { staging, manager })
136+
Ok(DirectInstall {
137+
staging,
138+
manager,
139+
name: None,
140+
})
141+
}
142+
143+
pub fn with_name(manager: PackageManager, name: String) -> Fallible<Self> {
144+
let staging = setup_staging_directory(manager, name.contains('/'))?;
145+
146+
Ok(DirectInstall {
147+
staging,
148+
manager,
149+
name: Some(name),
150+
})
136151
}
137152

138153
pub fn setup_command(&self, command: &mut Command) {
@@ -141,16 +156,20 @@ impl DirectInstall {
141156
}
142157

143158
pub fn complete_install(self, image: &Image) -> Fallible<()> {
144-
let name = self
145-
.manager
146-
.get_installed_package(self.staging.path().to_owned())
159+
let DirectInstall {
160+
staging,
161+
name,
162+
manager,
163+
} = self;
164+
165+
let name = name
166+
.or_else(|| manager.get_installed_package(staging.path().to_owned()))
147167
.ok_or(ErrorKind::InstalledPackageNameError)?;
148-
let manifest =
149-
configure::parse_manifest(&name, self.staging.path().to_owned(), self.manager)?;
168+
let manifest = configure::parse_manifest(&name, staging.path().to_owned(), manager)?;
150169

151-
persist_install(&name, &manifest.version, self.staging.path())?;
152-
link_package_to_shared_dir(&name, self.manager)?;
153-
configure::write_config_and_shims(&name, &manifest, image, self.manager)
170+
persist_install(&name, &manifest.version, staging.path())?;
171+
link_package_to_shared_dir(&name, manager)?;
172+
configure::write_config_and_shims(&name, &manifest, image, manager)
154173
}
155174
}
156175

@@ -211,17 +230,22 @@ impl InPlaceUpgrade {
211230

212231
/// Create the temporary staging directory we will use to install and ensure expected
213232
/// subdirectories exist within it
214-
fn setup_staging_directory(manager: PackageManager) -> Fallible<TempDir> {
233+
fn setup_staging_directory(manager: PackageManager, needs_scope: bool) -> Fallible<TempDir> {
215234
// Workaround to ensure relative symlinks continue to work.
216235
// The final installed location of packages is:
217236
// $VOLTA_HOME/tools/image/packages/{name}/
218237
// To ensure that the temp directory has the same amount of nesting, we use:
219238
// $VOLTA_HOME/tmp/image/packages/{tempdir}/
220239
// This way any relative symlinks will have the same amount of nesting and will remain valid
221240
// even when the directory is persisted.
241+
// We also need to handle the case when the linked package has a scope, which requires another
242+
// level of nesting
222243
let mut staging_root = volta_home()?.tmp_dir().to_owned();
223244
staging_root.push("image");
224245
staging_root.push("packages");
246+
if needs_scope {
247+
staging_root.push("scope");
248+
}
225249
create_dir_all(&staging_root).with_context(|| ErrorKind::ContainingDirError {
226250
path: staging_root.clone(),
227251
})?;

0 commit comments

Comments
 (0)