Repository: conda/conda-build

Issue:
Relative path in source causes rm_rf to remove linked source files
from https://github.com/conda/conda-build/pull/1598#issuecomment-272691858

@msarahan this commit (specifically these lines as found by running git bisect) - causes some odd behaviour - seen here. It seems that if you have a script in your project then the rm_rf call traverses the possibly? sym-linked script file and thus deletes the script in the original repository. This also may only be an issue for recipes built where the source is next to the recipe folder and thus copied using a relative path:

source:
  path: ../

To be clear:

After this commit, after the test phase the bin/lsfm script is deleted from inside the repository and not just from the work/build environment.


Discussion:
Thanks for adding as an issue - didn't raise in case something I did was wrong 😄 

Resolving patch:
diff --git a/conda_build/api.py b/conda_build/api.py
--- a/conda_build/api.py
+++ b/conda_build/api.py
@@ -62,6 +62,9 @@ def build(recipe_paths_or_metadata, post=None, need_source_download=True,
     from conda_build.conda_interface import string_types
     from conda_build.utils import find_recipe
 
+    assert post in (None, True, False), ("post must be boolean or None.  Remember, you must pass "
+                                         "other arguments (config) by keyword.")
+
     config = get_or_merge_config(config, **kwargs)
 
     recipe_paths_or_metadata = _ensure_list(recipe_paths_or_metadata)
@@ -80,10 +83,14 @@ def build(recipe_paths_or_metadata, post=None, need_source_download=True,
     recipes.extend(metadata)
     absolute_recipes = []
     for recipe in recipes:
-        if hasattr(recipe, "config") or os.path.isabs(recipe):
+        if hasattr(recipe, "config"):
             absolute_recipes.append(recipe)
         else:
-            absolute_recipes.append(os.path.normpath(os.path.join(os.getcwd(), recipe)))
+            if not os.path.isabs(recipe):
+                recipe = os.path.normpath(os.path.join(os.getcwd(), recipe))
+            if not os.path.exists(recipe):
+                raise ValueError("Path to recipe did not exist: {}".format(recipe))
+            absolute_recipes.append(recipe)
 
     return build_tree(absolute_recipes, build_only=build_only, post=post, notest=notest,
                       need_source_download=need_source_download, config=config)


Test patch:
diff --git a/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/bin/lsfm b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/bin/lsfm
new file mode 100755
--- /dev/null
+++ b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/bin/lsfm
@@ -0,0 +1,3 @@
+#!/usr/bin/env python
+
+print("yeehaw")
diff --git a/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/conda/meta.yaml b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/conda/meta.yaml
new file mode 100644
--- /dev/null
+++ b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/conda/meta.yaml
@@ -0,0 +1,16 @@
+# regression test for https://github.com/conda/conda-build/issues/1661
+
+package:
+  name: test_rm_rf_does_not_follow_links
+  version: 1.0
+
+source:
+  path: ../
+
+build:
+  script: python setup.py install --single-version-externally-managed --record=record.txt
+
+requirements:
+  build:
+    - python
+    - setuptools
diff --git a/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/conda/run_test.py b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/conda/run_test.py
new file mode 100644
--- /dev/null
+++ b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/conda/run_test.py
@@ -0,0 +1,3 @@
+import os
+
+assert os.path.isfile(os.path.join(os.getenv("PREFIX"), 'bin', 'lsfm'))
diff --git a/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/lsfm/__init__.py b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/lsfm/__init__.py
new file mode 100644
diff --git a/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/setup.py b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/setup.py
new file mode 100644
--- /dev/null
+++ b/tests/test-recipes/split-packages/_rm_rf_stays_within_prefix/setup.py
@@ -0,0 +1,8 @@
+from setuptools import setup
+from os.path import join
+
+setup(name='lsfm',
+      version="1.0",
+      modules=['lsfm'],
+      scripts=[join('bin', 'lsfm')],
+      )
diff --git a/tests/test_subpackages.py b/tests/test_subpackages.py
--- a/tests/test_subpackages.py
+++ b/tests/test_subpackages.py
@@ -19,6 +19,12 @@ def test_autodetect_raises_on_invalid_extension(test_config):
     with pytest.raises(NotImplementedError):
         api.build(os.path.join(subpackage_dir, '_invalid_script_extension'), config=test_config)
 
-
-# def test_all_subpackages_uploaded():
-#     raise NotImplementedError
+def test_rm_rf_does_not_follow_links(test_config):
+    recipe_dir = os.path.join(subpackage_dir, '_rm_rf_stays_within_prefix')
+    bin_file_that_disappears = os.path.join(recipe_dir, 'bin', 'lsfm')
+    if not os.path.isfile(bin_file_that_disappears):
+        with open(bin_file_that_disappears, 'w') as f:
+            f.write('weee')
+    assert os.path.isfile(bin_file_that_disappears)
+    api.build(os.path.join(recipe_dir, 'conda'), config=test_config)
+    assert os.path.isfile(bin_file_that_disappears)