diff options
| -rw-r--r-- | continuedev/src/continuedev/libs/util/paths.py | 6 | ||||
| -rw-r--r-- | continuedev/src/continuedev/plugins/context_providers/file.py | 2 | ||||
| -rw-r--r-- | continuedev/src/continuedev/server/ide.py | 12 | ||||
| -rw-r--r-- | continuedev/src/continuedev/server/ide_protocol.py | 4 | ||||
| -rw-r--r-- | continuedev/src/continuedev/server/meilisearch_server.py | 67 | ||||
| -rw-r--r-- | extension/src/activation/environmentSetup.ts | 35 | ||||
| -rw-r--r-- | extension/src/continueIdeClient.ts | 89 | 
7 files changed, 135 insertions, 80 deletions
| diff --git a/continuedev/src/continuedev/libs/util/paths.py b/continuedev/src/continuedev/libs/util/paths.py index b3e9ecc1..9f3117d0 100644 --- a/continuedev/src/continuedev/libs/util/paths.py +++ b/continuedev/src/continuedev/libs/util/paths.py @@ -31,6 +31,12 @@ def getServerFolderPath():      return path +def getMeilisearchExePath(): +    binary_name = "meilisearch.exe" if os.name == "nt" else "meilisearch" +    path = os.path.join(getServerFolderPath(), binary_name) +    return path + +  def getSessionFilePath(session_id: str):      path = os.path.join(getSessionsFolderPath(), f"{session_id}.json")      os.makedirs(os.path.dirname(path), exist_ok=True) diff --git a/continuedev/src/continuedev/plugins/context_providers/file.py b/continuedev/src/continuedev/plugins/context_providers/file.py index 9846dd3e..859088b8 100644 --- a/continuedev/src/continuedev/plugins/context_providers/file.py +++ b/continuedev/src/continuedev/plugins/context_providers/file.py @@ -123,7 +123,7 @@ class FileContextProvider(ContextProvider):          )      async def provide_context_items(self, workspace_dir: str) -> List[ContextItem]: -        contents = await self.sdk.ide.listDirectoryContents(workspace_dir) +        contents = await self.sdk.ide.listDirectoryContents(workspace_dir, True)          if contents is None:              return [] diff --git a/continuedev/src/continuedev/server/ide.py b/continuedev/src/continuedev/server/ide.py index 8a62c39e..89fcd0d1 100644 --- a/continuedev/src/continuedev/server/ide.py +++ b/continuedev/src/continuedev/server/ide.py @@ -494,10 +494,12 @@ class IdeProtocolServer(AbstractIdeProtocolServer):          )          return resp.fileEdit -    async def listDirectoryContents(self, directory: str) -> List[str]: +    async def listDirectoryContents( +        self, directory: str, recursive: bool = False +    ) -> List[str]:          """List the contents of a directory"""          resp = await self._send_and_receive_json( -            {"directory": directory}, +            {"directory": directory, "recursive": recursive},              ListDirectoryContentsResponse,              "listDirectoryContents",          ) @@ -574,7 +576,11 @@ async def websocket_endpoint(websocket: WebSocket, session_id: str = None):          # Start meilisearch          try: -            await start_meilisearch() + +            async def on_err(e): +                logger.debug(f"Failed to start MeiliSearch: {e}") + +            create_async_task(start_meilisearch(), on_err)          except Exception as e:              logger.debug("Failed to start MeiliSearch")              logger.debug(e) diff --git a/continuedev/src/continuedev/server/ide_protocol.py b/continuedev/src/continuedev/server/ide_protocol.py index 4ef4bde7..2a07ae2a 100644 --- a/continuedev/src/continuedev/server/ide_protocol.py +++ b/continuedev/src/continuedev/server/ide_protocol.py @@ -148,7 +148,9 @@ class AbstractIdeProtocolServer(ABC):          """Called when a file is saved"""      @abstractmethod -    async def listDirectoryContents(self, directory: str) -> List[str]: +    async def listDirectoryContents( +        self, directory: str, recursive: bool = False +    ) -> List[str]:          """List directory contents"""      @abstractmethod diff --git a/continuedev/src/continuedev/server/meilisearch_server.py b/continuedev/src/continuedev/server/meilisearch_server.py index 037ce8fa..390eeb50 100644 --- a/continuedev/src/continuedev/server/meilisearch_server.py +++ b/continuedev/src/continuedev/server/meilisearch_server.py @@ -3,20 +3,59 @@ import os  import shutil  import subprocess +import aiofiles +import aiohttp  from meilisearch_python_async import Client  from ..libs.util.logging import logger -from ..libs.util.paths import getServerFolderPath +from ..libs.util.paths import getMeilisearchExePath, getServerFolderPath -def ensure_meilisearch_installed() -> bool: +async def download_file(url: str, filename: str): +    async with aiohttp.ClientSession() as session: +        async with session.get(url) as resp: +            if resp.status == 200: +                f = await aiofiles.open(filename, mode="wb") +                await f.write(await resp.read()) +                await f.close() + + +async def download_meilisearch(): +    """ +    Downloads MeiliSearch. +    """ + +    serverPath = getServerFolderPath() +    logger.debug("Downloading MeiliSearch...") + +    if os.name == "nt": +        download_url = "https://github.com/meilisearch/meilisearch/releases/download/v1.3.2/meilisearch-windows-amd64.exe" +        download_path = getMeilisearchExePath() +        if not os.path.exists(download_path): +            await download_file(download_url, download_path) +            # subprocess.run( +            #     f"curl -L {download_url} -o {download_path}", +            #     shell=True, +            #     check=True, +            #     cwd=serverPath, +            # ) +    else: +        subprocess.run( +            "curl -L https://install.meilisearch.com | sh", +            shell=True, +            check=True, +            cwd=serverPath, +        ) + + +async def ensure_meilisearch_installed() -> bool:      """      Checks if MeiliSearch is installed.      Returns a bool indicating whether it was installed to begin with.      """      serverPath = getServerFolderPath() -    meilisearchPath = os.path.join(serverPath, "meilisearch") +    meilisearchPath = getMeilisearchExePath()      dumpsPath = os.path.join(serverPath, "dumps")      dataMsPath = os.path.join(serverPath, "data.ms") @@ -40,14 +79,7 @@ def ensure_meilisearch_installed() -> bool:          for p in existing_paths:              shutil.rmtree(p, ignore_errors=True) -        # Download MeiliSearch -        logger.debug("Downloading MeiliSearch...") -        subprocess.run( -            "curl -L https://install.meilisearch.com | sh", -            shell=True, -            check=True, -            cwd=serverPath, -        ) +        await download_meilisearch()          return False @@ -66,7 +98,7 @@ async def check_meilisearch_running() -> bool:                  if resp.status != "available":                      return False                  return True -            except Exception as e: +            except Exception:                  return False      except Exception:          return False @@ -86,24 +118,21 @@ async def start_meilisearch():      """      Starts the MeiliSearch server, wait for it.      """ - -    # Doesn't work on windows for now -    if not os.name == "posix": -        return -      serverPath = getServerFolderPath()      # Check if MeiliSearch is installed, if not download -    was_already_installed = ensure_meilisearch_installed() +    was_already_installed = await ensure_meilisearch_installed()      # Check if MeiliSearch is running      if not await check_meilisearch_running() or not was_already_installed:          logger.debug("Starting MeiliSearch...") +        binary_name = "meilisearch" if os.name == "nt" else "./meilisearch"          subprocess.Popen( -            ["./meilisearch", "--no-analytics"], +            [binary_name, "--no-analytics"],              cwd=serverPath,              stdout=subprocess.DEVNULL,              stderr=subprocess.STDOUT,              close_fds=True,              start_new_session=True, +            shell=True          ) diff --git a/extension/src/activation/environmentSetup.ts b/extension/src/activation/environmentSetup.ts index 7ca87768..3aa536d0 100644 --- a/extension/src/activation/environmentSetup.ts +++ b/extension/src/activation/environmentSetup.ts @@ -74,6 +74,14 @@ function serverVersionPath(): string {    return path.join(serverPath(), "server_version.txt");  } +function serverBinaryPath(): string { +  return path.join( +    serverPath(), +    "exe", +    `run${os.platform() === "win32" ? ".exe" : ""}` +  ); +} +  export function getExtensionVersion() {    const extension = vscode.extensions.getExtension("continue.continue");    return extension?.packageJSON.version || ""; @@ -105,14 +113,7 @@ async function checkOrKillRunningServer(serverUrl: string): Promise<boolean> {          // Try again, on Windows. This time with taskkill          if (os.platform() === "win32") {            try { -            const exePath = path.join( -              getExtensionUri().fsPath, -              "server", -              "exe", -              "run.exe" -            ); - -            await runCommand(`taskkill /F /IM ${exePath}`); +            await runCommand(`taskkill /F /IM run.exe`);            } catch (e: any) {              console.log(                "Failed to kill old server second time on windows with taskkill:", @@ -126,14 +127,9 @@ async function checkOrKillRunningServer(serverUrl: string): Promise<boolean> {        fs.unlinkSync(serverVersionPath());      }      // Also delete the server binary -    const serverBinaryPath = path.join( -      getExtensionUri().fsPath, -      "server", -      "exe", -      `run${os.platform() === "win32" ? ".exe" : ""}` -    ); -    if (fs.existsSync(serverBinaryPath)) { -      fs.unlinkSync(serverBinaryPath); +    const serverBinary = serverBinaryPath(); +    if (fs.existsSync(serverBinary)) { +      fs.unlinkSync(serverBinary);      }    } @@ -213,12 +209,7 @@ export async function startContinuePythonServer(redownload: boolean = true) {          : "mac/run"        : "linux/run"; -  const destination = path.join( -    getExtensionUri().fsPath, -    "server", -    "exe", -    `run${os.platform() === "win32" ? ".exe" : ""}` -  ); +  const destination = serverBinaryPath();    // First, check if the server is already downloaded    let shouldDownload = true; diff --git a/extension/src/continueIdeClient.ts b/extension/src/continueIdeClient.ts index 94997d76..353584e9 100644 --- a/extension/src/continueIdeClient.ts +++ b/extension/src/continueIdeClient.ts @@ -272,40 +272,10 @@ class IdeProtocolClient {          break;        case "listDirectoryContents":          messenger.send("listDirectoryContents", { -          contents: ( -            await vscode.workspace.fs.readDirectory( -              uriFromFilePath(data.directory) -            ) -          ) -            .map(([name, type]) => name) -            .filter((name) => { -              const DEFAULT_IGNORE_DIRS = [ -                ".git", -                ".vscode", -                ".idea", -                ".vs", -                ".venv", -                "env", -                ".env", -                "node_modules", -                "dist", -                "build", -                "target", -                "out", -                "bin", -                ".pytest_cache", -                ".vscode-test", -                ".continue", -                "__pycache__", -              ]; -              if ( -                !DEFAULT_IGNORE_DIRS.some((dir) => -                  name.split(path.sep).includes(dir) -                ) -              ) { -                return name; -              } -            }), +          contents: await this.getDirectoryContents( +            data.directory, +            data.recursive || false +          ),          });          break;        case "editFile": @@ -562,6 +532,57 @@ class IdeProtocolClient {        });    } +  async getDirectoryContents( +    directory: string, +    recursive: boolean +  ): Promise<string[]> { +    let nameAndType = ( +      await vscode.workspace.fs.readDirectory(uriFromFilePath(directory)) +    ).filter(([name, type]) => { +      const DEFAULT_IGNORE_DIRS = [ +        ".git", +        ".vscode", +        ".idea", +        ".vs", +        ".venv", +        "env", +        ".env", +        "node_modules", +        "dist", +        "build", +        "target", +        "out", +        "bin", +        ".pytest_cache", +        ".vscode-test", +        ".continue", +        "__pycache__", +      ]; +      if ( +        !DEFAULT_IGNORE_DIRS.some((dir) => name.split(path.sep).includes(dir)) +      ) { +        return name; +      } +    }); + +    let absolutePaths = nameAndType +      .filter(([name, type]) => type === vscode.FileType.File) +      .map(([name, type]) => path.join(directory, name)); +    if (recursive) { +      for (const [name, type] of nameAndType) { +        if (type === vscode.FileType.Directory) { +          const subdirectory = path.join(directory, name); +          const subdirectoryContents = await this.getDirectoryContents( +            subdirectory, +            recursive +          ); +          absolutePaths = absolutePaths.concat(subdirectoryContents); +        } +      } +    } +    return absolutePaths; +  } +    async readFile(filepath: string): Promise<string> {      let contents: string | undefined;      if (typeof contents === "undefined") { | 
