diff --git a/commands/instances.go b/commands/instances.go index 0b5127f0b8b..9eb26c96f4c 100644 --- a/commands/instances.go +++ b/commands/instances.go @@ -371,7 +371,11 @@ func (s *arduinoCoreServerImpl) Init(req *rpc.InitRequest, stream rpc.ArduinoCor if libraryRef.InstallDir != nil { libDir := libraryRef.InstallDir if !libDir.IsAbs() { - libDir = paths.New(req.GetSketchPath()).JoinPath(libraryRef.InstallDir) + sk, err := sketch.New(paths.New(req.GetSketchPath())) + if err != nil { + return &cmderrors.InvalidArgumentError{Cause: err} + } + libDir = sk.FullPath.JoinPath(libraryRef.InstallDir) } if !libDir.IsDir() { return &cmderrors.InvalidArgumentError{ diff --git a/internal/cli/compile/compile.go b/internal/cli/compile/compile.go index 6a81499a236..e613609a800 100644 --- a/internal/cli/compile/compile.go +++ b/internal/cli/compile/compile.go @@ -332,8 +332,9 @@ func runCompileCommand(cmd *cobra.Command, args []string, srv rpc.ArduinoCoreSer libDir := paths.New(lib.GetInstallDir()) // If the library is installed in the sketch path, we want to output the relative path // to the sketch path, so that the sketch is portable. - if ok, err := libDir.IsInsideDir(sketchPath); err == nil && ok { - if ref, err := libDir.RelFrom(sketchPath); err == nil { + sketchDir := paths.New(sk.LocationPath) + if ok, err := libDir.IsInsideDir(sketchDir); err == nil && ok { + if ref, err := libDir.RelFrom(sketchDir); err == nil { libDir = paths.New(filepath.ToSlash(ref.String())) } } diff --git a/internal/integrationtest/sketch/profiles_test.go b/internal/integrationtest/sketch/profiles_test.go index ffc8295f3c6..eb8b6083b04 100644 --- a/internal/integrationtest/sketch/profiles_test.go +++ b/internal/integrationtest/sketch/profiles_test.go @@ -97,3 +97,75 @@ profiles: {"name": "MyLibOutside", "install_dir": ` + string(libOutsideJson) + `} ]`) } + +func TestRelativeLocalLib(t *testing.T) { + env, cli := integrationtest.CreateArduinoCLIWithEnvironment(t) + t.Cleanup(env.CleanUp) + + // Prepare the sketch with libraries + tmpDir, err := paths.MkTempDir("", "") + require.NoError(t, err) + t.Cleanup(func() { _ = tmpDir.RemoveAll }) + + sketchTemplate, err := paths.New("testdata", "SketchWithLibrary").Abs() + require.NoError(t, err) + + sketch := tmpDir.Join("SketchWithLibrary") + libInside := sketch.Join("libraries", "MyLib") + err = sketchTemplate.CopyDirTo(sketch) + require.NoError(t, err) + + libOutsideTemplate := sketchTemplate.Join("..", "MyLibOutside") + libOutside := sketch.Join("..", "MyLibOutside") + err = libOutsideTemplate.CopyDirTo(libOutside) + require.NoError(t, err) + + // Install the required core and libraries + _, _, err = cli.Run("core", "install", "arduino:avr@1.8.6") + require.NoError(t, err) + _, _, err = cli.Run("lib", "install", "Adafruit BusIO@1.17.1", "--no-overwrite") + require.NoError(t, err) + _, _, err = cli.Run("lib", "install", "Adafruit GFX Library@1.12.1", "--no-overwrite") + require.NoError(t, err) + _, _, err = cli.Run("lib", "install", "Adafruit SSD1306@2.5.14", "--no-overwrite") + require.NoError(t, err) + + // Check if the profile dump: + // - keeps libraries in the sketch with a relative path to the folder, not the .ino + out, _, err := cli.Run("compile", "-b", "arduino:avr:uno", + "--library", libInside.String(), + "--library", libOutside.String(), + "--dump-profile", + sketch.Join("SketchWithLibrary.ino").String()) + require.NoError(t, err) + require.Equal(t, strings.TrimSpace(` +profiles: + uno: + fqbn: arduino:avr:uno + platforms: + - platform: arduino:avr (1.8.6) + libraries: + - dir: libraries/MyLib + - dir: `+libOutside.String()+` + - Adafruit SSD1306 (2.5.14) + - Adafruit GFX Library (1.12.1) + - Adafruit BusIO (1.17.1) +`), strings.TrimSpace(string(out))) + + outRelative := strings.Replace(string(out), libOutside.String(), "../MyLibOutside", 1) + + // Dump the profile in the sketch directory and compile with it again + err = sketch.Join("sketch.yaml").WriteFile([]byte(outRelative)) + require.NoError(t, err) + out, _, err = cli.Run("compile", "-m", "uno", "--json", sketch.Join("SketchWithLibrary.ino").String()) + require.NoError(t, err) + // Check if local libraries are picked up correctly + libInsideJson, _ := json.Marshal(libInside.String()) + libOutsideJson, _ := json.Marshal(libOutside.String()) + j := requirejson.Parse(t, out).Query(".builder_result.used_libraries") + j.MustContain(` + [ + {"name": "MyLib", "install_dir": ` + string(libInsideJson) + `}, + {"name": "MyLibOutside", "install_dir": ` + string(libOutsideJson) + `} + ]`) +}