diff --git a/src/dist/component/components.rs b/src/dist/component/components.rs index 0335fcabfc..c46fa0a655 100644 --- a/src/dist/component/components.rs +++ b/src/dist/component/components.rs @@ -109,7 +109,16 @@ impl<'a> ComponentBuilder<'a> { .push(ComponentPart("dir".to_owned(), path.clone())); self.tx.copy_dir(&self.name, path, src) } - + pub fn move_file(&mut self, path: PathBuf, src: &Path) -> Result<()> { + self.parts + .push(ComponentPart("file".to_owned(), path.clone())); + self.tx.move_file(&self.name, path, src) + } + pub fn move_dir(&mut self, path: PathBuf, src: &Path) -> Result<()> { + self.parts + .push(ComponentPart("dir".to_owned(), path.clone())); + self.tx.move_dir(&self.name, path, src) + } pub fn finish(mut self) -> Result> { // Write component manifest let path = self.components.rel_component_manifest(&self.name); diff --git a/src/dist/component/package.rs b/src/dist/component/package.rs index 6db9f93206..b83dbb6ed3 100644 --- a/src/dist/component/package.rs +++ b/src/dist/component/package.rs @@ -35,10 +35,11 @@ pub trait Package: fmt::Debug { pub struct DirectoryPackage { path: PathBuf, components: HashSet, + copy: bool, } impl DirectoryPackage { - pub fn new(path: PathBuf) -> Result { + pub fn new(path: PathBuf, copy: bool) -> Result { validate_installer_version(&path)?; let content = utils::read_file("package components", &path.join("components"))?; @@ -46,6 +47,7 @@ impl DirectoryPackage { Ok(DirectoryPackage { path: path, components: components, + copy: copy, }) } } @@ -97,8 +99,20 @@ impl Package for DirectoryPackage { let src_path = root.join(&path); match &*part.0 { - "file" => builder.copy_file(path.clone(), &src_path)?, - "dir" => builder.copy_dir(path.clone(), &src_path)?, + "file" => { + if self.copy { + builder.copy_file(path.clone(), &src_path)? + } else { + builder.move_file(path.clone(), &src_path)? + } + } + "dir" => { + if self.copy { + builder.copy_dir(path.clone(), &src_path)? + } else { + builder.move_dir(path.clone(), &src_path)? + } + } _ => return Err(ErrorKind::CorruptComponent(name.to_owned()).into()), } @@ -187,7 +201,7 @@ impl<'a> TarPackage<'a> { unpack_without_first_dir(&mut archive, &*temp_dir)?; Ok(TarPackage( - DirectoryPackage::new(temp_dir.to_owned())?, + DirectoryPackage::new(temp_dir.to_owned(), false)?, temp_dir, )) } diff --git a/src/dist/component/transaction.rs b/src/dist/component/transaction.rs index 127a854d02..1edd65489f 100644 --- a/src/dist/component/transaction.rs +++ b/src/dist/component/transaction.rs @@ -133,6 +133,22 @@ impl<'a> Transaction<'a> { Ok(()) } + /// Move a file to a relative path of the install prefix. + pub fn move_file(&mut self, component: &str, relpath: PathBuf, src: &Path) -> Result<()> { + assert!(relpath.is_relative()); + let item = ChangedItem::move_file(&self.prefix, component, relpath, src)?; + self.change(item); + Ok(()) + } + + /// Recursively move a directory to a relative path of the install prefix. + pub fn move_dir(&mut self, component: &str, relpath: PathBuf, src: &Path) -> Result<()> { + assert!(relpath.is_relative()); + let item = ChangedItem::move_dir(&self.prefix, component, relpath, src)?; + self.change(item); + Ok(()) + } + pub fn temp(&self) -> &'a temp::Cfg { self.temp_cfg } @@ -195,8 +211,12 @@ impl<'a> ChangedItem<'a> { } Ok(()) } - fn add_file(prefix: &InstallPrefix, component: &str, relpath: PathBuf) -> Result<(Self, File)> { - let abs_path = prefix.abs_path(&relpath); + fn dest_abs_path( + prefix: &InstallPrefix, + component: &str, + relpath: &PathBuf, + ) -> Result { + let abs_path = prefix.abs_path(relpath); if utils::path_exists(&abs_path) { Err(ErrorKind::ComponentConflict { name: component.to_owned(), @@ -207,32 +227,24 @@ impl<'a> ChangedItem<'a> { if let Some(p) = abs_path.parent() { utils::ensure_dir_exists("component", p, &|_| ())?; } - let file = File::create(&abs_path) - .chain_err(|| format!("error creating file '{}'", abs_path.display()))?; - - Ok((ChangedItem::AddedFile(relpath), file)) + Ok(abs_path) } } + fn add_file(prefix: &InstallPrefix, component: &str, relpath: PathBuf) -> Result<(Self, File)> { + let abs_path = ChangedItem::dest_abs_path(prefix, component, &relpath)?; + let file = File::create(&abs_path) + .chain_err(|| format!("error creating file '{}'", abs_path.display()))?; + Ok((ChangedItem::AddedFile(relpath), file)) + } fn copy_file( prefix: &InstallPrefix, component: &str, relpath: PathBuf, src: &Path, ) -> Result { - let abs_path = prefix.abs_path(&relpath); - if utils::path_exists(&abs_path) { - Err(ErrorKind::ComponentConflict { - name: component.to_owned(), - path: relpath.clone(), - } - .into()) - } else { - if let Some(p) = abs_path.parent() { - utils::ensure_dir_exists("component", p, &|_| ())?; - } - utils::copy_file(src, &abs_path)?; - Ok(ChangedItem::AddedFile(relpath)) - } + let abs_path = ChangedItem::dest_abs_path(prefix, component, &relpath)?; + utils::copy_file(src, &abs_path)?; + Ok(ChangedItem::AddedFile(relpath)) } fn copy_dir( prefix: &InstallPrefix, @@ -240,20 +252,9 @@ impl<'a> ChangedItem<'a> { relpath: PathBuf, src: &Path, ) -> Result { - let abs_path = prefix.abs_path(&relpath); - if utils::path_exists(&abs_path) { - Err(ErrorKind::ComponentConflict { - name: component.to_owned(), - path: relpath.clone(), - } - .into()) - } else { - if let Some(p) = abs_path.parent() { - utils::ensure_dir_exists("component", p, &|_| ())?; - } - utils::copy_dir(src, &abs_path, &|_| ())?; - Ok(ChangedItem::AddedDir(relpath)) - } + let abs_path = ChangedItem::dest_abs_path(prefix, component, &relpath)?; + utils::copy_dir(src, &abs_path, &|_| ())?; + Ok(ChangedItem::AddedDir(relpath)) } fn remove_file( prefix: &InstallPrefix, @@ -311,4 +312,24 @@ impl<'a> ChangedItem<'a> { Ok(ChangedItem::ModifiedFile(relpath, None)) } } + fn move_file( + prefix: &InstallPrefix, + component: &str, + relpath: PathBuf, + src: &Path, + ) -> Result { + let abs_path = ChangedItem::dest_abs_path(prefix, component, &relpath)?; + utils::rename_file("component", src, &abs_path)?; + Ok(ChangedItem::AddedFile(relpath)) + } + fn move_dir( + prefix: &InstallPrefix, + component: &str, + relpath: PathBuf, + src: &Path, + ) -> Result { + let abs_path = ChangedItem::dest_abs_path(prefix, component, &relpath)?; + utils::rename_dir("component", src, &abs_path)?; + Ok(ChangedItem::AddedDir(relpath)) + } } diff --git a/tests/dist_install.rs b/tests/dist_install.rs index 7e5ea1a27b..50deb4aa3d 100644 --- a/tests/dist_install.rs +++ b/tests/dist_install.rs @@ -67,7 +67,7 @@ fn package_contains() { mock.build(tempdir.path()); - let package = DirectoryPackage::new(tempdir.path().to_owned()).unwrap(); + let package = DirectoryPackage::new(tempdir.path().to_owned(), true).unwrap(); assert!(package.contains("mycomponent", None)); assert!(package.contains("mycomponent2", None)); } @@ -88,7 +88,7 @@ fn package_bad_version() { let mut ver = File::create(tempdir.path().join("rust-installer-version")).unwrap(); writeln!(ver, "100").unwrap(); - assert!(DirectoryPackage::new(tempdir.path().to_owned()).is_err()); + assert!(DirectoryPackage::new(tempdir.path().to_owned(), true).is_err()); } #[test] @@ -122,7 +122,7 @@ fn basic_install() { let components = Components::open(prefix.clone()).unwrap(); - let pkg = DirectoryPackage::new(pkgdir.path().to_owned()).unwrap(); + let pkg = DirectoryPackage::new(pkgdir.path().to_owned(), true).unwrap(); let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); tx.commit(); @@ -168,7 +168,7 @@ fn multiple_component_install() { let components = Components::open(prefix.clone()).unwrap(); - let pkg = DirectoryPackage::new(pkgdir.path().to_owned()).unwrap(); + let pkg = DirectoryPackage::new(pkgdir.path().to_owned(), true).unwrap(); let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); let tx = pkg.install(&components, "mycomponent2", None, tx).unwrap(); @@ -218,7 +218,7 @@ fn uninstall() { let components = Components::open(prefix.clone()).unwrap(); - let pkg = DirectoryPackage::new(pkgdir.path().to_owned()).unwrap(); + let pkg = DirectoryPackage::new(pkgdir.path().to_owned(), true).unwrap(); let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); let tx = pkg.install(&components, "mycomponent2", None, tx).unwrap(); @@ -275,7 +275,7 @@ fn component_bad_version() { let components = Components::open(prefix.clone()).unwrap(); - let pkg = DirectoryPackage::new(pkgdir.path().to_owned()).unwrap(); + let pkg = DirectoryPackage::new(pkgdir.path().to_owned(), true).unwrap(); let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); tx.commit(); @@ -336,7 +336,7 @@ fn unix_permissions() { let components = Components::open(prefix.clone()).unwrap(); - let pkg = DirectoryPackage::new(pkgdir.path().to_owned()).unwrap(); + let pkg = DirectoryPackage::new(pkgdir.path().to_owned(), true).unwrap(); let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); tx.commit(); @@ -421,7 +421,7 @@ fn install_to_prefix_that_does_not_exist() { let components = Components::open(prefix.clone()).unwrap(); - let pkg = DirectoryPackage::new(pkgdir.path().to_owned()).unwrap(); + let pkg = DirectoryPackage::new(pkgdir.path().to_owned(), true).unwrap(); let tx = pkg.install(&components, "mycomponent", None, tx).unwrap(); tx.commit();