Skip to content

Commit ae1535f

Browse files
committed
worker: Implement sync_to_git/sparse_index() jobs
1 parent edcc0ac commit ae1535f

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

src/background_jobs.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ pub enum Job {
1818
IndexAddCrate(IndexAddCrateJob),
1919
IndexSquash,
2020
IndexSyncToHttp(IndexSyncToHttpJob),
21+
SyncToGitIndex(SyncToIndexJob),
22+
SyncToSparseIndex(SyncToIndexJob),
2123
IndexUpdateYanked(IndexUpdateYankedJob),
2224
NormalizeIndex(NormalizeIndexJob),
2325
RenderAndUploadReadme(RenderAndUploadReadmeJob),
@@ -47,8 +49,22 @@ impl Job {
4749
const INDEX_UPDATE_YANKED: &str = "sync_yanked";
4850
const NORMALIZE_INDEX: &str = "normalize_index";
4951
const RENDER_AND_UPLOAD_README: &str = "render_and_upload_readme";
52+
const SYNC_TO_GIT_INDEX: &str = "sync_to_git_index";
53+
const SYNC_TO_SPARSE_INDEX: &str = "sync_to_sparse_index";
5054
const UPDATE_DOWNLOADS: &str = "update_downloads";
5155

56+
pub fn sync_to_git_index<T: ToString>(krate: T) -> Job {
57+
Job::SyncToGitIndex(SyncToIndexJob {
58+
krate: krate.to_string(),
59+
})
60+
}
61+
62+
pub fn sync_to_sparse_index<T: ToString>(krate: T) -> Job {
63+
Job::SyncToSparseIndex(SyncToIndexJob {
64+
krate: krate.to_string(),
65+
})
66+
}
67+
5268
fn as_type_str(&self) -> &'static str {
5369
match self {
5470
Job::DailyDbMaintenance => Self::DAILY_DB_MAINTENANCE,
@@ -59,6 +75,8 @@ impl Job {
5975
Job::IndexUpdateYanked(_) => Self::INDEX_UPDATE_YANKED,
6076
Job::NormalizeIndex(_) => Self::NORMALIZE_INDEX,
6177
Job::RenderAndUploadReadme(_) => Self::RENDER_AND_UPLOAD_README,
78+
Job::SyncToGitIndex(_) => Self::SYNC_TO_GIT_INDEX,
79+
Job::SyncToSparseIndex(_) => Self::SYNC_TO_SPARSE_INDEX,
6280
Job::UpdateDownloads => Self::UPDATE_DOWNLOADS,
6381
}
6482
}
@@ -73,6 +91,8 @@ impl Job {
7391
Job::IndexUpdateYanked(inner) => serde_json::to_value(inner),
7492
Job::NormalizeIndex(inner) => serde_json::to_value(inner),
7593
Job::RenderAndUploadReadme(inner) => serde_json::to_value(inner),
94+
Job::SyncToGitIndex(inner) => serde_json::to_value(inner),
95+
Job::SyncToSparseIndex(inner) => serde_json::to_value(inner),
7696
Job::UpdateDownloads => Ok(serde_json::Value::Null),
7797
}
7898
}
@@ -101,6 +121,8 @@ impl Job {
101121
Self::INDEX_UPDATE_YANKED => Job::IndexUpdateYanked(from_value(value)?),
102122
Self::NORMALIZE_INDEX => Job::NormalizeIndex(from_value(value)?),
103123
Self::RENDER_AND_UPLOAD_README => Job::RenderAndUploadReadme(from_value(value)?),
124+
Self::SYNC_TO_GIT_INDEX => Job::SyncToGitIndex(from_value(value)?),
125+
Self::SYNC_TO_SPARSE_INDEX => Job::SyncToSparseIndex(from_value(value)?),
104126
Self::UPDATE_DOWNLOADS => Job::UpdateDownloads,
105127
job_type => Err(PerformError::from(format!("Unknown job type {job_type}")))?,
106128
})
@@ -136,6 +158,8 @@ impl Job {
136158
args.base_url.as_deref(),
137159
args.pkg_path_in_vcs.as_deref(),
138160
),
161+
Job::SyncToGitIndex(args) => worker::sync_to_git_index(env, conn, &args.krate),
162+
Job::SyncToSparseIndex(args) => worker::sync_to_sparse_index(env, conn, &args.krate),
139163
Job::UpdateDownloads => worker::perform_update_downloads(&mut *fresh_connection(pool)?),
140164
}
141165
}
@@ -172,6 +196,11 @@ pub struct IndexSyncToHttpJob {
172196
pub(super) crate_name: String,
173197
}
174198

199+
#[derive(Serialize, Deserialize)]
200+
pub struct SyncToIndexJob {
201+
pub(super) krate: String,
202+
}
203+
175204
#[derive(Serialize, Deserialize)]
176205
pub struct IndexUpdateYankedJob {
177206
pub(super) krate: String,

src/worker/git.rs

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use crate::background_jobs::{
22
Environment, IndexAddCrateJob, IndexSyncToHttpJob, IndexUpdateYankedJob, Job, NormalizeIndexJob,
33
};
4+
use crate::models;
45
use crate::schema;
56
use crate::swirl::PerformError;
67
use anyhow::Context;
78
use cargo_registry_index::{Crate, Repository};
89
use chrono::Utc;
910
use diesel::prelude::*;
10-
use std::fs::{self, OpenOptions};
11-
use std::io::{BufRead, BufReader, ErrorKind};
11+
use std::fs::{self, File, OpenOptions};
12+
use std::io::{BufRead, BufReader, ErrorKind, Write};
1213
use std::process::Command;
1314

1415
#[instrument(skip_all, fields(krate.name = ?krate.name, krate.vers = ?krate.vers))]
@@ -74,6 +75,98 @@ pub fn update_crate_index(crate_name: String) -> Job {
7475
Job::IndexSyncToHttp(IndexSyncToHttpJob { crate_name })
7576
}
7677

78+
/// Regenerates or removes an index file for a single crate
79+
#[instrument(skip_all, fields(krate.name = ?krate))]
80+
pub fn sync_to_git_index(
81+
env: &Environment,
82+
conn: &mut PgConnection,
83+
krate: &str,
84+
) -> Result<(), PerformError> {
85+
info!("Syncing to git index");
86+
87+
let new = get_index_data(krate, conn).context("Failed to get index data")?;
88+
89+
let repo = env.lock_index()?;
90+
let dst = repo.index_file(krate);
91+
92+
// Read the previous crate contents
93+
let old = match fs::read_to_string(&dst) {
94+
Ok(content) => Some(content),
95+
Err(error) if error.kind() == ErrorKind::NotFound => None,
96+
Err(error) => return Err(error.into()),
97+
};
98+
99+
match (old, new) {
100+
(None, Some(new)) => {
101+
fs::create_dir_all(dst.parent().unwrap())?;
102+
let mut file = File::create(&dst)?;
103+
file.write_all(new.as_bytes())?;
104+
repo.commit_and_push(&format!("Creating crate `{}`", krate), &dst)?;
105+
}
106+
(Some(old), Some(new)) if old != new => {
107+
let mut file = File::create(&dst)?;
108+
file.write_all(new.as_bytes())?;
109+
repo.commit_and_push(&format!("Updating crate `{}`", krate), &dst)?;
110+
}
111+
(Some(_old), None) => {
112+
fs::remove_file(&dst)?;
113+
repo.commit_and_push(&format!("Deleting crate `{}`", krate), &dst)?;
114+
}
115+
_ => debug!("Skipping sync because index is up-to-date"),
116+
}
117+
118+
Ok(())
119+
}
120+
121+
/// Regenerates or removes an index file for a single crate
122+
#[instrument(skip_all, fields(krate.name = ?krate))]
123+
pub fn sync_to_sparse_index(
124+
env: &Environment,
125+
conn: &mut PgConnection,
126+
krate: &str,
127+
) -> Result<(), PerformError> {
128+
info!("Syncing to sparse index");
129+
130+
let content = get_index_data(krate, conn).context("Failed to get index data")?;
131+
132+
env.uploader
133+
.sync_index(env.http_client(), krate, content)
134+
.context("Failed to sync index data")?;
135+
136+
if let Some(cloudfront) = env.cloudfront() {
137+
let path = Repository::relative_index_file_for_url(krate);
138+
139+
info!(%path, "Invalidating index file on CloudFront");
140+
cloudfront
141+
.invalidate(env.http_client(), &path)
142+
.context("Failed to invalidate CloudFront")?;
143+
}
144+
145+
Ok(())
146+
}
147+
148+
#[instrument(skip_all, fields(krate.name = ?name))]
149+
pub fn get_index_data(name: &str, conn: &mut PgConnection) -> anyhow::Result<Option<String>> {
150+
debug!("Looking up crate by name");
151+
let Some(krate): Option<models::Crate> = models::Crate::by_exact_name(name).first(conn).optional()? else {
152+
return Ok(None);
153+
};
154+
155+
debug!("Gathering remaining index data");
156+
let crates = krate
157+
.index_metadata(conn)
158+
.context("Failed to gather index metadata")?;
159+
160+
debug!("Serializing index data");
161+
let mut bytes = Vec::new();
162+
cargo_registry_index::write_crates(&crates, &mut bytes)
163+
.context("Failed to serialize index metadata")?;
164+
165+
let str = String::from_utf8(bytes).context("Failed to decode index metadata as utf8")?;
166+
167+
Ok(Some(str))
168+
}
169+
77170
/// Yanks or unyanks a crate version. This requires finding the index
78171
/// file, deserlialise the crate from JSON, change the yank boolean to
79172
/// `true` or `false`, write all the lines back out, and commit and

src/worker/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ pub(crate) use daily_db_maintenance::perform_daily_db_maintenance;
2020
pub(crate) use dump_db::perform_dump_db;
2121
pub(crate) use git::{
2222
perform_index_add_crate, perform_index_squash, perform_index_sync_to_http,
23-
perform_index_update_yanked, perform_normalize_index,
23+
perform_index_update_yanked, perform_normalize_index, sync_to_git_index, sync_to_sparse_index,
2424
};
2525
pub(crate) use readmes::perform_render_and_upload_readme;
2626
pub(crate) use update_downloads::perform_update_downloads;

0 commit comments

Comments
 (0)