binaryninja/repository/
manager.rs

1use crate::rc::{Array, Ref, RefCountable};
2use crate::repository::Repository;
3use crate::string::IntoCStr;
4use binaryninjacore_sys::{
5    BNCreateRepositoryManager, BNFreeRepositoryManager, BNGetRepositoryManager,
6    BNNewRepositoryManagerReference, BNRepositoryGetRepositoryByPath, BNRepositoryManager,
7    BNRepositoryManagerAddRepository, BNRepositoryManagerCheckForUpdates,
8    BNRepositoryManagerGetDefaultRepository, BNRepositoryManagerGetRepositories,
9};
10use std::fmt::Debug;
11use std::path::Path;
12use std::ptr::NonNull;
13
14/// Keeps track of all the repositories and keeps the `enabled_plugins.json`
15/// file coherent with the plugins that are installed/uninstalled enabled/disabled
16#[repr(transparent)]
17pub struct RepositoryManager {
18    handle: NonNull<BNRepositoryManager>,
19}
20
21impl RepositoryManager {
22    #[allow(clippy::should_implement_trait)]
23    pub fn default() -> Ref<Self> {
24        let result = unsafe { BNGetRepositoryManager() };
25        unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) }
26    }
27
28    pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNRepositoryManager>) -> Ref<Self> {
29        Ref::new(Self { handle })
30    }
31
32    pub fn new(plugins_path: &str) -> Ref<Self> {
33        let plugins_path = plugins_path.to_cstr();
34        let result = unsafe { BNCreateRepositoryManager(plugins_path.as_ptr()) };
35        unsafe { Self::ref_from_raw(NonNull::new(result).unwrap()) }
36    }
37
38    /// Check for updates for all managed [`Repository`] objects
39    pub fn check_for_updates(&self) -> bool {
40        unsafe { BNRepositoryManagerCheckForUpdates(self.handle.as_ptr()) }
41    }
42
43    /// List of [`Repository`] objects being managed
44    pub fn repositories(&self) -> Array<Repository> {
45        let mut count = 0;
46        let result =
47            unsafe { BNRepositoryManagerGetRepositories(self.handle.as_ptr(), &mut count) };
48        assert!(!result.is_null());
49        unsafe { Array::new(result, count, ()) }
50    }
51
52    /// Adds a new plugin repository for the manager to track.
53    ///
54    /// To remove a repository, restart Binary Ninja (and don't re-add the repository!).
55    /// File artifacts will remain on disk under repositories/ file in the User Folder.
56    ///
57    /// Before you can query plugin metadata from a repository, you need to call [`RepositoryManager::check_for_updates`].
58    ///
59    /// * `url` - URL to the plugins.json containing the records for this repository
60    /// * `repository_path` - path to where the repository will be stored on disk locally
61    ///
62    /// Returns true if the repository was successfully added, false otherwise.
63    pub fn add_repository(&self, url: &str, repository_path: &Path) -> bool {
64        let url = url.to_cstr();
65        let repo_path = repository_path.to_cstr();
66        unsafe {
67            BNRepositoryManagerAddRepository(self.handle.as_ptr(), url.as_ptr(), repo_path.as_ptr())
68        }
69    }
70
71    pub fn repository_by_path(&self, path: &Path) -> Option<Repository> {
72        let path = path.to_cstr();
73        let result =
74            unsafe { BNRepositoryGetRepositoryByPath(self.handle.as_ptr(), path.as_ptr()) };
75        NonNull::new(result).map(|raw| unsafe { Repository::from_raw(raw) })
76    }
77
78    /// Gets the default [`Repository`]
79    pub fn default_repository(&self) -> Ref<Repository> {
80        let result = unsafe { BNRepositoryManagerGetDefaultRepository(self.handle.as_ptr()) };
81        assert!(!result.is_null());
82        unsafe { Repository::ref_from_raw(NonNull::new(result).unwrap()) }
83    }
84}
85
86impl Debug for RepositoryManager {
87    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
88        f.debug_struct("RepositoryManager")
89            .field("repositories", &self.repositories().to_vec())
90            .finish()
91    }
92}
93
94impl ToOwned for RepositoryManager {
95    type Owned = Ref<Self>;
96
97    fn to_owned(&self) -> Self::Owned {
98        unsafe { RefCountable::inc_ref(self) }
99    }
100}
101
102unsafe impl RefCountable for RepositoryManager {
103    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
104        Self::ref_from_raw(
105            NonNull::new(BNNewRepositoryManagerReference(handle.handle.as_ptr())).unwrap(),
106        )
107    }
108
109    unsafe fn dec_ref(handle: &Self) {
110        BNFreeRepositoryManager(handle.handle.as_ptr())
111    }
112}