Dark Mode

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 0a11eb2

Browse files
committed
Pipfile.lock Dependency Parser
Built this today to help fix an old development environment. https://gist.github.com/simonw/e13064e2e830db77887373ced5df1b5b
1 parent a57b5c3 commit 0a11eb2

File tree

2 files changed

+202
-0
lines changed
  • README.md
  • pipfile.html

2 files changed

+202
-0
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ This collection is partly **an experiment** in how much it's possible to get don
3030
- [Word Counter](https://tools.simonwillison.net/word-counter) - count words across multiple blocks of text, persisted to localStorage
3131
- [PHP Deserializer](https://tools.simonwillison.net/php-deserializer) - paste in serealized PHP data, get back JSON
3232
- [SQL Pretty Printer](https://tools.simonwillison.net/sql-pretty-printer) - paste in SQL to pretty print it
33+
- [SQL Pretty Printer](https://tools.simonwillison.net/sql-pretty-printer) - paste in SQL to pretty print it
34+
- [Pipfile.lock Dependency Parser](https://tools.simonwillison.net/pipfile) - paste in a `Pipfile.lock` JSON file to extract just the dependency versions
3335

3436
## LLM playgrounds and debuggers
3537

pipfile.html

Lines changed: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
1+
>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Pipfile.lock Dependency Parsertitle>
7+
<style>
8+
* {
9+
box-sizing: border-box;
10+
}
11+
12+
body {
13+
font-family: Helvetica, Arial, sans-serif;
14+
line-height: 1.6;
15+
max-width: 800px;
16+
margin: 0 auto;
17+
padding: 20px;
18+
color: #333;
19+
}
20+
21+
h1 {
22+
margin-top: 0;
23+
}
24+
25+
textarea {
26+
width: 100%;
27+
height: 300px;
28+
padding: 10px;
29+
margin-bottom: 15px;
30+
border: 1px solid #ccc;
31+
border-radius: 4px;
32+
font-size: 16px;
33+
font-family: monospace;
34+
}
35+
36+
button {
37+
background-color: #4CAF50;
38+
color: white;
39+
border: none;
40+
padding: 10px 15px;
41+
cursor: pointer;
42+
border-radius: 4px;
43+
font-size: 16px;
44+
}
45+
46+
button:hover {
47+
background-color: #45a049;
48+
}
49+
50+
pre {
51+
background-color: #f5f5f5;
52+
padding: 15px;
53+
border-radius: 4px;
54+
overflow-x: auto;
55+
white-space: pre-wrap;
56+
margin-top: 20px;
57+
}
58+
59+
.error {
60+
color: #d9534f;
61+
margin-top: 10px;
62+
}
63+
64+
.controls {
65+
display: flex;
66+
gap: 10px;
67+
margin-bottom: 15px;
68+
}
69+
style>
70+
head>
71+
<body>
72+
<h1>Pipfile.lock Dependency Parserh1>
73+
<p>Paste your Pipfile.lock content below and click "Parse" to extract dependencies with their versions.p>
74+
75+
<textarea id="input" placeholder="Paste Pipfile.lock content here...">textarea>
76+
77+
<div class="controls">
78+
<button id="parseBtn">Parse Dependenciesbutton>
79+
<button id="copyPipfileBtn">Copy Pipfile Formatbutton>
80+
<button id="copyReqsBtn">Copy Requirements.txtbutton>
81+
<button id="clearBtn">Clear Allbutton>
82+
div>
83+
84+
<div id="error" class="error">div>
85+
86+
<h2>Pipfile Format:h2>
87+
<pre id="output">pre>
88+
89+
<h2>Requirements.txt Format:h2>
90+
<pre id="reqsOutput">pre>
91+
92+
<script type="module">
93+
// Parse the Pipfile.lock content and extract dependencies
94+
function parsePipfileLock(content) {
95+
try {
96+
// Parse the JSON content
97+
const data = JSON.parse(content);
98+
let pipfileFormat = [];
99+
let reqsFormat = [];
100+
101+
// Process dependencies from "default" section
102+
if (data.default) {
103+
for (const [name, info] of Object.entries(data.default)) {
104+
if (info.version) {
105+
// Extract version without the '==' prefix
106+
const version = info.version.replace(/^==/, '');
107+
pipfileFormat.push(`"${name}" = "==${version}"`);
108+
reqsFormat.push(`${name}==${version}`);
109+
}
110+
}
111+
}
112+
113+
// Process dependencies from "develop" section if needed
114+
if (data.develop) {
115+
for (const [name, info] of Object.entries(data.develop)) {
116+
if (info.version) {
117+
const version = info.version.replace(/^==/, '');
118+
pipfileFormat.push(`"${name}" = "==${version}"`);
119+
reqsFormat.push(`${name}==${version}`);
120+
}
121+
}
122+
}
123+
124+
return {
125+
pipfileFormat: pipfileFormat.join('\n'),
126+
reqsFormat: reqsFormat.join('\n')
127+
};
128+
} catch (error) {
129+
throw new Error(`Failed to parse Pipfile.lock: ${error.message}`);
130+
}
131+
}
132+
133+
// Set up event handlers
134+
document.getElementById('parseBtn').addEventListener('click', () => {
135+
const input = document.getElementById('input').value.trim();
136+
const pipfileOutputEl = document.getElementById('output');
137+
const reqsOutputEl = document.getElementById('reqsOutput');
138+
const errorEl = document.getElementById('error');
139+
140+
errorEl.textContent = '';
141+
142+
if (!input) {
143+
errorEl.textContent = 'Please paste Pipfile.lock content first.';
144+
return;
145+
}
146+
147+
try {
148+
const result = parsePipfileLock(input);
149+
pipfileOutputEl.textContent = result.pipfileFormat;
150+
reqsOutputEl.textContent = result.reqsFormat;
151+
} catch (error) {
152+
errorEl.textContent = error.message;
153+
}
154+
});
155+
156+
function copyToClipboard(text, successMessage) {
157+
if (!text) {
158+
document.getElementById('error').textContent = 'No content to copy.';
159+
return;
160+
}
161+
162+
navigator.clipboard.writeText(text)
163+
.then(() => {
164+
const errorEl = document.getElementById('error');
165+
errorEl.textContent = successMessage || 'Output copied to clipboard!';
166+
errorEl.style.color = '#4CAF50';
167+
setTimeout(() => {
168+
errorEl.textContent = '';
169+
errorEl.style.color = '#d9534f';
170+
}, 2000);
171+
})
172+
.catch(err => {
173+
document.getElementById('error').textContent = 'Failed to copy: ' + err;
174+
});
175+
}
176+
177+
document.getElementById('copyPipfileBtn').addEventListener('click', () => {
178+
const output = document.getElementById('output').textContent;
179+
copyToClipboard(output, 'Pipfile format copied to clipboard!');
180+
});
181+
182+
document.getElementById('copyReqsBtn').addEventListener('click', () => {
183+
const output = document.getElementById('reqsOutput').textContent;
184+
copyToClipboard(output, 'Requirements.txt format copied to clipboard!');
185+
});
186+
187+
document.getElementById('clearBtn').addEventListener('click', () => {
188+
document.getElementById('input').value = '';
189+
document.getElementById('output').textContent = '';
190+
document.getElementById('error').textContent = '';
191+
});
192+
193+
// Initialize with example data from the textarea if present
194+
const initialContent = document.getElementById('input').value.trim();
195+
if (initialContent) {
196+
document.getElementById('parseBtn').click();
197+
}
198+
script>
199+
body>
200+
html>

0 commit comments

Comments
(0)