Merge ~nteodosio/software-properties:xenial-ua into software-properties:ubuntu/master

Proposed by Nathan Teodosio
Status: Superseded
Proposed branch: ~nteodosio/software-properties:xenial-ua
Merge into: software-properties:ubuntu/master
Diff against target: 1639 lines (+976/-2) (has conflicts)
17 files modified
add-apt-repository (+34/-0)
data/gtkbuilder/dialog-ua-attach.ui (+33/-0)
data/gtkbuilder/main.ui (+155/-0)
data/ubuntu-pro-logo.svg (+28/-1)
debian/changelog (+83/-0)
debian/control (+19/-0)
debian/software-properties-gtk.install (+5/-0)
po/POTFILES.in (+4/-0)
softwareproperties/SoftwareProperties.py (+36/-1)
softwareproperties/cloudarchive.py (+21/-0)
softwareproperties/gtk/DialogUaAttach.py (+33/-0)
softwareproperties/gtk/SoftwarePropertiesGtk.py (+92/-0)
softwareproperties/gtk/UbuntuProPage.py (+10/-0)
softwareproperties/gtk/utils.py (+27/-0)
softwareproperties/ppa.py (+345/-0)
softwareproperties/shortcuts.py (+5/-0)
tests/test_shortcuts.py (+46/-0)
Conflict in add-apt-repository
Conflict in data/gtkbuilder/dialog-ua-attach.ui
Conflict in data/gtkbuilder/main.ui
Conflict in data/ubuntu-pro-logo.svg
Conflict in debian/changelog
Conflict in debian/control
Conflict in debian/software-properties-gtk.install
Conflict in po/POTFILES.in
Conflict in softwareproperties/SoftwareProperties.py
Conflict in softwareproperties/cloudarchive.py
Conflict in softwareproperties/gtk/DialogUaAttach.py
Conflict in softwareproperties/gtk/SoftwarePropertiesGtk.py
Conflict in softwareproperties/gtk/UbuntuProPage.py
Conflict in softwareproperties/gtk/utils.py
Conflict in softwareproperties/ppa.py
Conflict in softwareproperties/shortcuts.py
Conflict in tests/test_shortcuts.py
Reviewer Review Type Date Requested Status
Sebastien Bacher Pending
Review via email: mp+455630@code.launchpad.net

Description of the change

0.96.20.11[1] was blocked in proposed because of syntax error[2] in a exception with Xenial's old Python.

We committed the fix already but need to release it yet, for we should coordinate LP:1990450 (update-manager) with LP:2029473 (software-properties) on Xenial.

[1] https://git.launchpad.net/software-properties/commit/?id=f2e294b194184fef230a4012e057955f2b097a6c
[2] https://autopkgtest.ubuntu.com/results/autopkgtest-xenial/xenial/amd64/s/software-properties/20231026_095741_b43a1@/log.gz

To post a comment you must log in.

Unmerged commits

7d9f5be... by Nathan Teodosio

Release software-properties 0.96.20.12.

4cbf8e7... by Nathan Teodosio

Fix invalid syntax and unused import.

f2e294b... by Sebastien Bacher

releasing package software-properties version 0.96.20.11

09a94a9... by Sebastien Bacher

Update translatable sources

a57fef4... by Nathan Teodosio

Add comment explaining why we need to decode to UTF8.

d9c3635... by Nathan Teodosio

Do not block on daemon thread.

Would happen upon exiting after launching Enable Ubuntu Pro.

bdd470d... by Nathan Teodosio

Only decode to UTF8 if coming from ua call.

b3b28a9... by Nathan Teodosio

Add SVG to .install

b4c2e04... by Nathan Teodosio

status_json.decode("utf-8")

To avoid JSON object must be str, not bytes

71b072d... by Nathan Teodosio

Depend on python3-distro-info and ubuntu-advantage-{tools,desktop-daemon}.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1diff --git a/add-apt-repository b/add-apt-repository
2index 985cae9..bf6dc41 100755
3--- a/add-apt-repository
4+++ b/add-apt-repository
5@@ -203,6 +203,7 @@ class AddAptRepository(object):
6 if (s.uri, suite) in binary_entries:
7 binary_entries[(s.uri, suite)].append(s)
8 else:
9+<<<<<<< add-apt-repository
10 binary_entries[(s.uri, suite)] = [s]
11
12 for (uri, suite), entries in binary_entries.items():
13@@ -228,6 +229,39 @@ class AddAptRepository(object):
14 if get_source_entry_pocket(e) == 'release':
15 comps += e.comps
16 comps = list(set(comps))
17+=======
18+ print(_("'%s' distribution component is already enabled for all sources.") % line)
19+ sys.exit(0)
20+ sp.sourceslist.save()
21+ sys.exit(0)
22+
23+ # this wasn't a component name ('multiverse', 'backports'), so its either
24+ # a actual line to be added or a shortcut.
25+ try:
26+ shortcut = shortcut_handler(line)
27+ except ShortcutException as e:
28+ print(e)
29+ sys.exit(1)
30+
31+ # display more information about the shortcut / ppa info
32+ if not options.assume_yes and shortcut.should_confirm():
33+ try:
34+ info = shortcut.info()
35+ except ShortcutException as e:
36+ print(e)
37+ sys.exit(1)
38+
39+ # strip ANSI escape sequences
40+ description = re.sub(r"(\x9B|\x1B\[)[0-?]*[ -/]*[@-~]",
41+ "", info["description"] or "")
42+
43+ print(" %s" % description)
44+ print(_(" More info: %s") % str(info["web_link"]))
45+ if (sys.stdin.isatty() and
46+ not "FORCE_ADD_APT_REPOSITORY" in os.environ):
47+ if options.remove:
48+ print(_("Press [ENTER] to continue or ctrl-c to cancel removing it"))
49+>>>>>>> add-apt-repository
50 else:
51 comps = ['main', 'restricted']
52
53diff --git a/data/gtkbuilder/dialog-ua-attach.ui b/data/gtkbuilder/dialog-ua-attach.ui
54index 1445b82..0f0f195 100644
55--- a/data/gtkbuilder/dialog-ua-attach.ui
56+++ b/data/gtkbuilder/dialog-ua-attach.ui
57@@ -39,6 +39,10 @@
58 <property name="margin-top">30</property>
59 <property name="xalign">0</property>
60 <property name="group">magic_radio</property>
61+<<<<<<< data/gtkbuilder/dialog-ua-attach.ui
62+=======
63+ <signal name="toggled" handler="on_radio_toggled" swapped="no"/>
64+>>>>>>> data/gtkbuilder/dialog-ua-attach.ui
65 <signal name="clicked" handler="on_magic_radio_clicked" swapped="no"/>
66 </object>
67 </child>
68@@ -48,6 +52,7 @@
69 <property name="can-focus">False</property>
70 <property name="orientation">horizontal</property>
71 <child>
72+<<<<<<< data/gtkbuilder/dialog-ua-attach.ui
73 <object class="GtkLabel" id="pin_label">
74 <property name="label"> </property>
75 <property name="visible">True</property>
76@@ -61,6 +66,30 @@
77 <attributes>
78 <attribute name="scale" value="2"/>
79 </attributes>
80+=======
81+ <object class="GtkBox" id="pin_label_box">
82+ <property name="visible">True</property>
83+ <property name="margin-left">20</property>
84+ <property name="margin-top">12</property>
85+ <property name="margin-bottom">8</property>
86+ <property name="can-focus">False</property>
87+ <child>
88+ <object class="GtkLabel" id="pin_label">
89+ <property name="label"> </property>
90+ <property name="visible">True</property>
91+ <property name="selectable">True</property>
92+ <property name="can-focus">False</property>
93+ <property name="halign">start</property>
94+ <property name="margin-left">6</property>
95+ <property name="margin-right">6</property>
96+ <property name="margin-top">4</property>
97+ <property name="margin-bottom">4</property>
98+ <attributes>
99+ <attribute name="scale" value="2"/>
100+ </attributes>
101+ </object>
102+ </child>
103+>>>>>>> data/gtkbuilder/dialog-ua-attach.ui
104 </object>
105 </child>
106 <child>
107@@ -68,6 +97,10 @@
108 <property name="visible">True</property>
109 <property name="valign">center</property>
110 <property name="margin">3</property>
111+<<<<<<< data/gtkbuilder/dialog-ua-attach.ui
112+=======
113+ <property name="margin-left">9</property>
114+>>>>>>> data/gtkbuilder/dialog-ua-attach.ui
115 <child>
116 <object class="GtkSpinner" id="pin_spinner">
117 <property name="visible">True</property>
118diff --git a/data/gtkbuilder/main.ui b/data/gtkbuilder/main.ui
119index 9c3551b..ac6b91c 100644
120--- a/data/gtkbuilder/main.ui
121+++ b/data/gtkbuilder/main.ui
122@@ -539,6 +539,33 @@
123 <property name="position">0</property>
124 </packing>
125 </child>
126+<<<<<<< data/gtkbuilder/main.ui
127+=======
128+ </object>
129+ <packing>
130+ <property name="expand">False</property>
131+ <property name="fill">True</property>
132+ </packing>
133+ </child>
134+ <child>
135+ <object class="GtkLabel">
136+ <property name="visible">True</property>
137+ <property name="can_focus">False</property>
138+ <property name="label" translatable="yes">Snap package updates are checked routinely and installed automatically.</property>
139+ <property name="xalign">0</property>
140+ </object>
141+ <packing>
142+ <property name="expand">False</property>
143+ <property name="fill">False</property>
144+ </packing>
145+ </child>
146+ <child>
147+ <object class="GtkAlignment" id="alignment2">
148+ <property name="visible">True</property>
149+ <property name="can_focus">False</property>
150+ <property name="top_padding">6</property>
151+ <property name="left_padding">12</property>
152+>>>>>>> data/gtkbuilder/main.ui
153 <child>
154 <object class="GtkAlignment">
155 <property name="visible">True</property>
156@@ -546,7 +573,103 @@
157 <property name="top_padding">6</property>
158 <property name="left_padding">12</property>
159 <child>
160+<<<<<<< data/gtkbuilder/main.ui
161 <object class="GtkVBox">
162+=======
163+ <object class="GtkHBox">
164+ <property name="visible">True</property>
165+ <property name="can_focus">False</property>
166+ <property name="spacing">6</property>
167+ <child>
168+ <object class="GtkLabel" id="label_esm_heading">
169+ <property name="visible">True</property>
170+ <property name="can_focus">False</property>
171+ <property name="xalign">1</property>
172+ <property name="label" translatable="yes">For other packages, this system has:</property>
173+ </object>
174+ <packing>
175+ <property name="expand">False</property>
176+ <property name="fill">False</property>
177+ <property name="position">0</property>
178+ </packing>
179+ </child>
180+ <child>
181+ <object class="GtkHBox">
182+ <property name="visible">True</property>
183+ <property name="can_focus">False</property>
184+ <property name="spacing">6</property>
185+ <child>
186+ <object class="GtkLabel" id="label_esm_status">
187+ <property name="visible">True</property>
188+ <property name="can_focus">False</property>
189+ <property name="xalign">0</property>
190+ </object>
191+ <packing>
192+ <property name="expand">False</property>
193+ <property name="fill">True</property>
194+ </packing>
195+ </child>
196+ <child>
197+ <object class="GtkLabel" id="label_esm_subscribe">
198+ <property name="visible">True</property>
199+ <property name="can_focus">False</property>
200+ <property name="xalign">1</property>
201+ </object>
202+ <packing>
203+ <property name="expand">True</property>
204+ <property name="fill">True</property>
205+ </packing>
206+ </child>
207+ </object>
208+ <packing>
209+ <property name="expand">True</property>
210+ <property name="fill">True</property>
211+ <property name="position">1</property>
212+ </packing>
213+ </child>
214+ </object>
215+ <packing>
216+ <property name="expand">False</property>
217+ <property name="fill">False</property>
218+ </packing>
219+ </child>
220+ <child>
221+ <object class="GtkHBox">
222+ <property name="visible">True</property>
223+ <property name="can_focus">False</property>
224+ <property name="spacing">6</property>
225+ <child>
226+ <object class="GtkLabel" id="label_eol_heading">
227+ <property name="visible">True</property>
228+ <property name="can_focus">False</property>
229+ </object>
230+ <packing>
231+ <property name="expand">False</property>
232+ <property name="fill">False</property>
233+ <property name="position">0</property>
234+ </packing>
235+ </child>
236+ <child>
237+ <object class="GtkLabel" id="label_eol">
238+ <property name="visible">True</property>
239+ <property name="can_focus">False</property>
240+ <property name="xalign">0</property>
241+ </object>
242+ <packing>
243+ <property name="expand">True</property>
244+ <property name="fill">True</property>
245+ <property name="position">1</property>
246+ </packing>
247+ </child>
248+ </object>
249+ <packing>
250+ <property name="expand">False</property>
251+ <property name="fill">False</property>
252+ </packing>
253+ </child>
254+ <child>
255+ <object class="GtkHBox" id="hbox_check_for_updates">
256+>>>>>>> data/gtkbuilder/main.ui
257 <property name="visible">True</property>
258 <property name="can_focus">False</property>
259 <property name="spacing">6</property>
260@@ -1236,7 +1359,11 @@
261 </child>
262 <child>
263 <object class="GtkStack" id="stack_ua_main">
264+<<<<<<< data/gtkbuilder/main.ui
265 <property name="visible">False</property>
266+=======
267+ <property name="visible">True</property>
268+>>>>>>> data/gtkbuilder/main.ui
269 <child>
270 <object class="GtkBox" id="box_ua_options">
271 <property name="visible">True</property>
272@@ -1376,6 +1503,10 @@ Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machi
273 <child>
274 <object class="GtkLabel" id="label_ua_esm_infra_error">
275 <property name="visible">False</property>
276+<<<<<<< data/gtkbuilder/main.ui
277+=======
278+ <property name="label" translatable="yes">Could not enable ESM Infra. Please try again.</property>
279+>>>>>>> data/gtkbuilder/main.ui
280 <property name="valign">center</property>
281 <property name="xalign">0</property>
282 <attributes>
283@@ -1413,6 +1544,10 @@ Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machi
284 <child>
285 <object class="GtkLabel" id="label_ua_esm_apps_error">
286 <property name="visible">False</property>
287+<<<<<<< data/gtkbuilder/main.ui
288+=======
289+ <property name="label" translatable="yes">Could not enable ESM Apps. Please try again.</property>
290+>>>>>>> data/gtkbuilder/main.ui
291 <property name="xalign">0</property>
292 <attributes>
293 <attribute name="foreground" value="red"/>
294@@ -1450,6 +1585,10 @@ Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machi
295 <child>
296 <object class="GtkLabel" id="label_ua_livepatch_error">
297 <property name="visible">False</property>
298+<<<<<<< data/gtkbuilder/main.ui
299+=======
300+ <property name="label" translatable="yes">Could not enable Livepatch. Please try again.</property>
301+>>>>>>> data/gtkbuilder/main.ui
302 <property name="xalign">0</property>
303 <attributes>
304 <attribute name="foreground" value="red"/>
305@@ -1534,7 +1673,11 @@ Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machi
306 <child>
307 <object class="GtkLabel" id="label_ua_fips_status">
308 <property name="visible">True</property>
309+<<<<<<< data/gtkbuilder/main.ui
310 <property name="label">&lt;b&gt;FIPS 140-2&lt;/b&gt;</property>
311+=======
312+ <property name="label" translatable="yes">&lt;b&gt;FIPS 140-2&lt;/b&gt;</property>
313+>>>>>>> data/gtkbuilder/main.ui
314 <property name="use_markup">True</property>
315 <property name="xalign">0</property>
316 </object>
317@@ -1713,6 +1856,7 @@ Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machi
318 <child type="titlebar">
319 <placeholder/>
320 </child>
321+<<<<<<< data/gtkbuilder/main.ui
322 </object>
323 <object class="GtkSizeGroup">
324 <widgets>
325@@ -1724,14 +1868,25 @@ Receive security updates for over 25,000 Ubuntu packages, free for up to 5 machi
326 <widget name="label_updates_6"/>
327 <widget name="label_updates_7"/>
328 </widgets>
329+=======
330+>>>>>>> data/gtkbuilder/main.ui
331 </object>
332 <object class="GtkSizeGroup">
333 <widgets>
334+<<<<<<< data/gtkbuilder/main.ui
335 <widget name="combobox_updates_subscription"/>
336 <widget name="combobox_update_interval"/>
337 <widget name="combobox_security_updates"/>
338 <widget name="combobox_other_updates"/>
339 <widget name="combobox_release_upgrades"/>
340+=======
341+ <widget name="label_esm_heading"/>
342+ <widget name="label_eol_heading"/>
343+ <widget name="label3"/>
344+ <widget name="label4"/>
345+ <widget name="label5"/>
346+ <widget name="label29"/>
347+>>>>>>> data/gtkbuilder/main.ui
348 </widgets>
349 </object>
350 </interface>
351diff --git a/data/ubuntu-pro-logo.svg b/data/ubuntu-pro-logo.svg
352index b94971a..2ad3260 100644
353--- a/data/ubuntu-pro-logo.svg
354+++ b/data/ubuntu-pro-logo.svg
355@@ -1 +1,28 @@
356-<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.71 34"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#e95420;}.cls-3{fill:none;}</style></defs><g><path d="M31.74,29.47c-1.3,0-2.33-.25-3.1-.76-.77-.51-1.33-1.19-1.67-2.05-.34-.86-.51-1.81-.51-2.87V14.68h1.42v8.92c0,1.59,.36,2.75,1.07,3.49,.71,.74,1.64,1.11,2.8,1.11s2.09-.37,2.8-1.11c.71-.74,1.07-1.9,1.07-3.49V14.68h1.42v9.11c0,1.06-.17,2.02-.51,2.87s-.9,1.54-1.67,2.05-1.81,.76-3.1,.76Z"/><path d="M44.46,29.41c-.63,0-1.19-.03-1.68-.09-.49-.06-.93-.14-1.29-.23-.37-.09-.69-.18-.95-.26V13.2l1.36-.25v6.06c.24-.18,.62-.37,1.15-.57,.53-.2,1.14-.3,1.84-.3,1.04,0,1.93,.24,2.65,.72,.72,.48,1.28,1.15,1.66,2,.38,.85,.57,1.82,.57,2.92,0,1.17-.22,2.18-.67,3.02-.45,.84-1.06,1.49-1.86,1.94-.79,.45-1.72,.68-2.78,.68Zm-.02-1.23c.78,0,1.46-.17,2.04-.51,.58-.34,1.03-.84,1.36-1.5,.33-.66,.49-1.46,.49-2.39,0-.6-.06-1.16-.19-1.69-.13-.53-.33-1-.61-1.41-.28-.41-.64-.73-1.1-.96s-1.01-.34-1.68-.34-1.22,.11-1.73,.33c-.52,.22-.89,.43-1.13,.63v7.56c.21,.06,.52,.12,.94,.19,.42,.07,.95,.1,1.61,.1Z"/><path d="M56.74,29.37c-1.07,0-1.92-.21-2.55-.62-.63-.41-1.07-.99-1.34-1.73-.26-.75-.4-1.61-.4-2.6v-6.06h1.36v5.62c0,1.02,.1,1.83,.3,2.43,.2,.61,.53,1.04,.99,1.32,.46,.27,1.07,.41,1.84,.41,.64,0,1.2-.04,1.67-.1s.77-.13,.9-.19v-9.48h1.36v10.42c-.4,.11-.95,.24-1.63,.38-.68,.14-1.52,.21-2.51,.21Z"/><path d="M64.26,29.16v-10.42c.4-.11,.95-.24,1.64-.38,.69-.14,1.52-.21,2.5-.21,1.1,0,1.96,.21,2.58,.63,.62,.42,1.06,1,1.32,1.74,.26,.75,.39,1.61,.39,2.6v6.04h-1.36v-5.6c0-1.02-.09-1.83-.28-2.44-.19-.61-.51-1.05-.97-1.33-.46-.27-1.09-.41-1.88-.41-.64,0-1.19,.04-1.66,.1-.47,.07-.77,.13-.91,.19v9.48h-1.36Z"/><path d="M79.39,29.39c-.89,0-1.59-.16-2.11-.47s-.88-.78-1.09-1.41-.31-1.42-.31-2.38V15.19l1.36-.25v3.43h4.3v1.15h-4.3v5.74c0,.82,.09,1.44,.27,1.86,.18,.42,.44,.7,.78,.83,.34,.14,.73,.21,1.18,.21,.57,0,1.03-.07,1.38-.21,.35-.14,.62-.26,.81-.35l.33,1.13c-.2,.12-.54,.27-1.02,.43-.49,.16-1.02,.24-1.59,.24Z"/><path d="M88.09,29.37c-1.07,0-1.92-.21-2.55-.62-.63-.41-1.07-.99-1.34-1.73-.26-.75-.4-1.61-.4-2.6v-6.06h1.36v5.62c0,1.02,.1,1.83,.3,2.43,.2,.61,.53,1.04,.99,1.32,.46,.27,1.07,.41,1.84,.41,.64,0,1.2-.04,1.67-.1s.77-.13,.9-.19v-9.48h1.36v10.42c-.4,.11-.95,.24-1.63,.38-.68,.14-1.52,.21-2.51,.21Z"/><path d="M100.67,29.16V14.96c.5-.14,1.09-.24,1.77-.3,.67-.06,1.3-.09,1.89-.09,2.03,0,3.55,.39,4.56,1.18s1.51,1.89,1.51,3.31c0,1.1-.25,1.98-.76,2.64-.51,.66-1.24,1.14-2.18,1.43-.95,.29-2.08,.44-3.41,.44h-1.96v5.6h-1.42Zm1.42-6.83h1.8c1.02,0,1.9-.09,2.65-.26,.75-.17,1.34-.5,1.75-.98,.42-.48,.63-1.17,.63-2.06s-.22-1.51-.66-1.97c-.44-.47-1-.79-1.69-.98-.69-.19-1.42-.28-2.18-.28-.52,0-.96,.02-1.34,.05s-.7,.07-.96,.09v6.39Z"/><path d="M112.84,29.16v-10.3c.35-.15,.83-.31,1.44-.47,.61-.16,1.36-.24,2.24-.24,.29,0,.58,.02,.87,.05,.29,.04,.54,.08,.75,.12s.37,.09,.47,.14l-.27,1.17c-.1-.06-.32-.12-.67-.18-.35-.06-.8-.09-1.36-.09-.58,0-1.05,.04-1.41,.12-.35,.08-.59,.15-.7,.21v9.46h-1.36Z"/><path d="M124.62,29.41c-.96,0-1.81-.23-2.55-.7-.74-.47-1.32-1.12-1.74-1.97s-.64-1.84-.64-2.97,.21-2.13,.64-2.98c.42-.84,1.01-1.5,1.74-1.97s1.59-.71,2.55-.71,1.81,.24,2.56,.71c.74,.47,1.33,1.13,1.74,1.97,.42,.84,.63,1.83,.63,2.98s-.21,2.12-.63,2.97-1,1.51-1.74,1.97c-.75,.47-1.6,.7-2.56,.7Zm0-1.23c.71,0,1.33-.18,1.85-.54,.52-.36,.93-.87,1.21-1.54,.29-.66,.43-1.44,.43-2.33s-.14-1.69-.43-2.35-.69-1.17-1.21-1.54c-.52-.36-1.14-.54-1.85-.54s-1.33,.18-1.85,.54c-.52,.36-.93,.87-1.21,1.54-.29,.66-.43,1.45-.43,2.35s.14,1.67,.43,2.33c.29,.66,.69,1.17,1.21,1.54,.52,.36,1.14,.54,1.85,.54Z"/></g><g><rect class="cls-2" x="0" width="21" height="32"/><rect class="cls-3" x="2.5" y="14" width="16" height="16"/><circle class="cls-1" cx="4.8" cy="21.15" r="2.17"/><circle class="cls-1" cx="13.86" cy="16.39" r="2.17"/><path class="cls-1" d="M9.7,26.75c-1.57-.34-2.87-1.34-3.61-2.75-.58,.26-1.23,.34-1.86,.23,.89,2.19,2.78,3.77,5.1,4.27,.51,.11,1.03,.16,1.54,.16-.4-.52-.62-1.16-.64-1.82-.18-.02-.36-.05-.53-.09Z"/><circle class="cls-1" cx="13.37" cy="26.76" r="2.17"/><path class="cls-1" d="M16.39,25.96c.68-.85,1.15-1.86,1.38-2.93,.4-1.87,.03-3.83-1.03-5.42-.25,.59-.68,1.09-1.22,1.43,.59,1.11,.77,2.38,.5,3.61-.13,.6-.36,1.17-.68,1.68,.51,.42,.87,.98,1.04,1.62Z"/><path class="cls-1" d="M4.63,18.04c.06,0,.11,0,.17,0,.22,0,.44,.02,.66,.07,.35,.08,.69,.21,.99,.4,.98-1.41,2.56-2.25,4.27-2.28,0-.16,.03-.33,.07-.49,.1-.47,.3-.9,.59-1.27-2.73-.22-5.39,1.19-6.74,3.58Z"/></g></svg>
357\ No newline at end of file
358+<<<<<<< data/ubuntu-pro-logo.svg
359+<?xml version="1.0" encoding="UTF-8"?><svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 130.71 34"><defs><style>.cls-1{fill:#fff;}.cls-2{fill:#e95420;}.cls-3{fill:none;}</style></defs><g><path d="M31.74,29.47c-1.3,0-2.33-.25-3.1-.76-.77-.51-1.33-1.19-1.67-2.05-.34-.86-.51-1.81-.51-2.87V14.68h1.42v8.92c0,1.59,.36,2.75,1.07,3.49,.71,.74,1.64,1.11,2.8,1.11s2.09-.37,2.8-1.11c.71-.74,1.07-1.9,1.07-3.49V14.68h1.42v9.11c0,1.06-.17,2.02-.51,2.87s-.9,1.54-1.67,2.05-1.81,.76-3.1,.76Z"/><path d="M44.46,29.41c-.63,0-1.19-.03-1.68-.09-.49-.06-.93-.14-1.29-.23-.37-.09-.69-.18-.95-.26V13.2l1.36-.25v6.06c.24-.18,.62-.37,1.15-.57,.53-.2,1.14-.3,1.84-.3,1.04,0,1.93,.24,2.65,.72,.72,.48,1.28,1.15,1.66,2,.38,.85,.57,1.82,.57,2.92,0,1.17-.22,2.18-.67,3.02-.45,.84-1.06,1.49-1.86,1.94-.79,.45-1.72,.68-2.78,.68Zm-.02-1.23c.78,0,1.46-.17,2.04-.51,.58-.34,1.03-.84,1.36-1.5,.33-.66,.49-1.46,.49-2.39,0-.6-.06-1.16-.19-1.69-.13-.53-.33-1-.61-1.41-.28-.41-.64-.73-1.1-.96s-1.01-.34-1.68-.34-1.22,.11-1.73,.33c-.52,.22-.89,.43-1.13,.63v7.56c.21,.06,.52,.12,.94,.19,.42,.07,.95,.1,1.61,.1Z"/><path d="M56.74,29.37c-1.07,0-1.92-.21-2.55-.62-.63-.41-1.07-.99-1.34-1.73-.26-.75-.4-1.61-.4-2.6v-6.06h1.36v5.62c0,1.02,.1,1.83,.3,2.43,.2,.61,.53,1.04,.99,1.32,.46,.27,1.07,.41,1.84,.41,.64,0,1.2-.04,1.67-.1s.77-.13,.9-.19v-9.48h1.36v10.42c-.4,.11-.95,.24-1.63,.38-.68,.14-1.52,.21-2.51,.21Z"/><path d="M64.26,29.16v-10.42c.4-.11,.95-.24,1.64-.38,.69-.14,1.52-.21,2.5-.21,1.1,0,1.96,.21,2.58,.63,.62,.42,1.06,1,1.32,1.74,.26,.75,.39,1.61,.39,2.6v6.04h-1.36v-5.6c0-1.02-.09-1.83-.28-2.44-.19-.61-.51-1.05-.97-1.33-.46-.27-1.09-.41-1.88-.41-.64,0-1.19,.04-1.66,.1-.47,.07-.77,.13-.91,.19v9.48h-1.36Z"/><path d="M79.39,29.39c-.89,0-1.59-.16-2.11-.47s-.88-.78-1.09-1.41-.31-1.42-.31-2.38V15.19l1.36-.25v3.43h4.3v1.15h-4.3v5.74c0,.82,.09,1.44,.27,1.86,.18,.42,.44,.7,.78,.83,.34,.14,.73,.21,1.18,.21,.57,0,1.03-.07,1.38-.21,.35-.14,.62-.26,.81-.35l.33,1.13c-.2,.12-.54,.27-1.02,.43-.49,.16-1.02,.24-1.59,.24Z"/><path d="M88.09,29.37c-1.07,0-1.92-.21-2.55-.62-.63-.41-1.07-.99-1.34-1.73-.26-.75-.4-1.61-.4-2.6v-6.06h1.36v5.62c0,1.02,.1,1.83,.3,2.43,.2,.61,.53,1.04,.99,1.32,.46,.27,1.07,.41,1.84,.41,.64,0,1.2-.04,1.67-.1s.77-.13,.9-.19v-9.48h1.36v10.42c-.4,.11-.95,.24-1.63,.38-.68,.14-1.52,.21-2.51,.21Z"/><path d="M100.67,29.16V14.96c.5-.14,1.09-.24,1.77-.3,.67-.06,1.3-.09,1.89-.09,2.03,0,3.55,.39,4.56,1.18s1.51,1.89,1.51,3.31c0,1.1-.25,1.98-.76,2.64-.51,.66-1.24,1.14-2.18,1.43-.95,.29-2.08,.44-3.41,.44h-1.96v5.6h-1.42Zm1.42-6.83h1.8c1.02,0,1.9-.09,2.65-.26,.75-.17,1.34-.5,1.75-.98,.42-.48,.63-1.17,.63-2.06s-.22-1.51-.66-1.97c-.44-.47-1-.79-1.69-.98-.69-.19-1.42-.28-2.18-.28-.52,0-.96,.02-1.34,.05s-.7,.07-.96,.09v6.39Z"/><path d="M112.84,29.16v-10.3c.35-.15,.83-.31,1.44-.47,.61-.16,1.36-.24,2.24-.24,.29,0,.58,.02,.87,.05,.29,.04,.54,.08,.75,.12s.37,.09,.47,.14l-.27,1.17c-.1-.06-.32-.12-.67-.18-.35-.06-.8-.09-1.36-.09-.58,0-1.05,.04-1.41,.12-.35,.08-.59,.15-.7,.21v9.46h-1.36Z"/><path d="M124.62,29.41c-.96,0-1.81-.23-2.55-.7-.74-.47-1.32-1.12-1.74-1.97s-.64-1.84-.64-2.97,.21-2.13,.64-2.98c.42-.84,1.01-1.5,1.74-1.97s1.59-.71,2.55-.71,1.81,.24,2.56,.71c.74,.47,1.33,1.13,1.74,1.97,.42,.84,.63,1.83,.63,2.98s-.21,2.12-.63,2.97-1,1.51-1.74,1.97c-.75,.47-1.6,.7-2.56,.7Zm0-1.23c.71,0,1.33-.18,1.85-.54,.52-.36,.93-.87,1.21-1.54,.29-.66,.43-1.44,.43-2.33s-.14-1.69-.43-2.35-.69-1.17-1.21-1.54c-.52-.36-1.14-.54-1.85-.54s-1.33,.18-1.85,.54c-.52,.36-.93,.87-1.21,1.54-.29,.66-.43,1.45-.43,2.35s.14,1.67,.43,2.33c.29,.66,.69,1.17,1.21,1.54,.52,.36,1.14,.54,1.85,.54Z"/></g><g><rect class="cls-2" x="0" width="21" height="32"/><rect class="cls-3" x="2.5" y="14" width="16" height="16"/><circle class="cls-1" cx="4.8" cy="21.15" r="2.17"/><circle class="cls-1" cx="13.86" cy="16.39" r="2.17"/><path class="cls-1" d="M9.7,26.75c-1.57-.34-2.87-1.34-3.61-2.75-.58,.26-1.23,.34-1.86,.23,.89,2.19,2.78,3.77,5.1,4.27,.51,.11,1.03,.16,1.54,.16-.4-.52-.62-1.16-.64-1.82-.18-.02-.36-.05-.53-.09Z"/><circle class="cls-1" cx="13.37" cy="26.76" r="2.17"/><path class="cls-1" d="M16.39,25.96c.68-.85,1.15-1.86,1.38-2.93,.4-1.87,.03-3.83-1.03-5.42-.25,.59-.68,1.09-1.22,1.43,.59,1.11,.77,2.38,.5,3.61-.13,.6-.36,1.17-.68,1.68,.51,.42,.87,.98,1.04,1.62Z"/><path class="cls-1" d="M4.63,18.04c.06,0,.11,0,.17,0,.22,0,.44,.02,.66,.07,.35,.08,.69,.21,.99,.4,.98-1.41,2.56-2.25,4.27-2.28,0-.16,.03-.33,.07-.49,.1-.47,.3-.9,.59-1.27-2.73-.22-5.39,1.19-6.74,3.58Z"/></g></svg>
360+=======
361+<?xml version="1.0" encoding="UTF-8"?>
362+<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1579.82 400">
363+ <g>
364+ <path d="m381.87,354.01c-11.69,0-21.64-1.78-29.85-5.33-8.22-3.56-14.86-8.47-19.94-14.74-5.08-6.26-8.77-13.59-11.05-21.98-2.29-8.38-3.43-17.4-3.43-27.06v-110.77h17.28v108.49c0,9.65,1.14,18,3.43,25.03,2.29,7.03,5.46,12.83,9.53,17.4,4.06,4.57,8.97,7.96,14.74,10.16,5.76,2.2,12.2,3.3,19.31,3.3s13.55-1.1,19.31-3.3c5.76-2.2,10.67-5.59,14.74-10.16s7.24-10.37,9.53-17.4c2.29-7.03,3.43-15.37,3.43-25.03v-108.49h17.28v110.77c0,9.65-1.14,18.67-3.43,27.06-2.29,8.38-5.97,15.71-11.05,21.98-5.08,6.27-11.73,11.18-19.94,14.74-8.22,3.56-18.17,5.33-29.85,5.33Z"/>
365+ <path d="m500.62,226.73c2.88-2.2,7.5-4.53,13.85-6.99,6.35-2.45,13.85-3.68,22.48-3.68,9.48,0,17.91,1.7,25.28,5.08,7.37,3.39,13.59,8.13,18.67,14.23,5.08,6.1,8.93,13.34,11.56,21.72,2.62,8.38,3.94,17.57,3.94,27.57,0,10.67-1.57,20.24-4.7,28.71-3.13,8.47-7.54,15.67-13.21,21.59-5.68,5.93-12.45,10.46-20.32,13.59-7.88,3.13-16.64,4.7-26.3,4.7-11.69,0-21.34-.76-28.96-2.29-7.62-1.52-13.89-3.13-18.8-4.83v-190.04l16.51-3.05v73.68Zm0,107.98c2.54.85,6.31,1.65,11.31,2.41,4.99.76,11.56,1.14,19.69,1.14,14.23,0,25.66-4.61,34.3-13.85,8.64-9.23,12.96-22.49,12.96-39.76,0-7.28-.76-14.18-2.29-20.71-1.52-6.52-3.98-12.19-7.37-17.02-3.39-4.83-7.84-8.68-13.34-11.56-5.51-2.88-12.32-4.32-20.45-4.32-3.9,0-7.62.38-11.18,1.14-3.56.76-6.86,1.74-9.91,2.92-3.05,1.19-5.72,2.46-8,3.81-2.29,1.36-4.19,2.63-5.72,3.81v91.97Z"/>
366+ <path d="m726.96,345.63c-4.91,1.36-11.52,2.88-19.82,4.57-8.3,1.69-18.46,2.54-30.49,2.54-9.82,0-18.04-1.44-24.64-4.32-6.61-2.88-11.94-6.94-16.01-12.2-4.06-5.25-6.99-11.6-8.76-19.05-1.78-7.45-2.67-15.67-2.67-24.64v-73.68h16.51v68.34c0,9.32.67,17.19,2.03,23.63,1.35,6.44,3.56,11.65,6.61,15.62,3.05,3.98,6.99,6.86,11.81,8.64,4.83,1.78,10.71,2.67,17.66,2.67,7.79,0,14.56-.42,20.33-1.27,5.76-.85,9.4-1.61,10.92-2.29v-115.34h16.51v126.78Z"/>
367+ <path d="m763.39,223.43c4.91-1.35,11.52-2.88,19.82-4.57,8.3-1.69,18.46-2.54,30.49-2.54,9.99,0,18.33,1.44,25.03,4.32,6.69,2.88,12.02,6.99,16.01,12.32,3.98,5.33,6.81,11.73,8.51,19.18,1.69,7.46,2.54,15.67,2.54,24.64v73.42h-16.51v-68.09c0-9.31-.63-17.19-1.91-23.63-1.27-6.44-3.39-11.69-6.35-15.75-2.96-4.07-6.86-6.99-11.69-8.77-4.83-1.78-10.88-2.67-18.17-2.67-7.79,0-14.53.42-20.2,1.27-5.68.85-9.36,1.61-11.05,2.29v115.34h-16.51v-126.78Z"/>
368+ <path d="m916.61,218.85h52.34v13.97h-52.34v69.87c0,7.46.63,13.51,1.9,18.17,1.27,4.66,3.09,8.26,5.46,10.8,2.37,2.54,5.25,4.24,8.64,5.08,3.38.85,7.11,1.27,11.18,1.27,6.94,0,12.53-.8,16.77-2.41,4.23-1.61,7.53-3.09,9.91-4.45l4.06,13.72c-2.37,1.52-6.52,3.26-12.45,5.21-5.93,1.95-12.37,2.92-19.31,2.92-8.13,0-14.95-1.06-20.45-3.18-5.51-2.12-9.91-5.34-13.21-9.65-3.3-4.32-5.63-9.69-6.99-16.13-1.36-6.43-2.03-14.06-2.03-22.87v-120.93l16.52-3.05v41.67Z"/>
369+ <path d="m1094.4,345.63c-4.91,1.36-11.52,2.88-19.82,4.57-8.3,1.69-18.46,2.54-30.49,2.54-9.82,0-18.04-1.44-24.64-4.32-6.61-2.88-11.94-6.94-16.01-12.2-4.06-5.25-6.99-11.6-8.76-19.05-1.78-7.45-2.67-15.67-2.67-24.64v-73.68h16.51v68.34c0,9.32.67,17.19,2.03,23.63,1.35,6.44,3.56,11.65,6.61,15.62,3.05,3.98,6.99,6.86,11.81,8.64,4.83,1.78,10.71,2.67,17.66,2.67,7.79,0,14.56-.42,20.32-1.27,5.76-.85,9.4-1.61,10.93-2.29v-115.34h16.51v126.78Z"/>
370+ <path d="m1241.5,172.61c24.9,0,43.44,4.74,55.64,14.23,12.2,9.49,18.29,22.95,18.29,40.4,0,10-1.78,18.51-5.34,25.53-3.56,7.03-8.64,12.7-15.24,17.02-6.61,4.32-14.7,7.46-24.26,9.4-9.57,1.95-20.37,2.92-32.39,2.92h-23.88v68.09h-17.28v-172.76c6.1-1.69,13.25-2.92,21.47-3.68,8.21-.76,15.88-1.14,22.99-1.14Zm.76,14.99c-6.44,0-11.9.21-16.39.63-4.49.42-8.35.81-11.56,1.14v77.74h21.85c9.31,0,17.74-.55,25.28-1.65,7.54-1.1,13.97-3.13,19.31-6.1,5.34-2.96,9.44-7.07,12.32-12.32,2.88-5.25,4.32-11.94,4.32-20.07s-1.57-14.23-4.7-19.31c-3.14-5.08-7.29-9.1-12.45-12.07-5.17-2.96-11.05-5.04-17.66-6.22-6.61-1.18-13.38-1.78-20.32-1.78Z"/>
371+ <path d="m1385.07,216.31c5.42,0,10.54.42,15.37,1.27,4.83.85,8.17,1.7,10.04,2.54l-3.3,14.23c-1.36-.67-4.11-1.4-8.26-2.16-4.15-.76-9.62-1.14-16.39-1.14-7.12,0-12.83.51-17.15,1.52-4.32,1.02-7.16,1.87-8.51,2.54v115.09h-16.51v-125.25c4.23-1.86,10.08-3.77,17.53-5.72,7.45-1.95,16.51-2.92,27.18-2.92Z"/>
372+ <path d="m1538.85,284.65c0,10.33-1.48,19.73-4.45,28.2-2.96,8.47-7.11,15.67-12.45,21.6-5.34,5.93-11.65,10.54-18.93,13.85-7.29,3.3-15.33,4.95-24.14,4.95s-16.86-1.65-24.13-4.95c-7.29-3.3-13.59-7.92-18.93-13.85-5.34-5.93-9.49-13.12-12.45-21.6-2.97-8.47-4.45-17.87-4.45-28.2s1.48-19.73,4.45-28.2c2.96-8.47,7.11-15.71,12.45-21.72,5.33-6.01,11.64-10.67,18.93-13.97,7.28-3.3,15.33-4.95,24.13-4.95s16.85,1.65,24.14,4.95c7.28,3.3,13.59,7.96,18.93,13.97,5.34,6.01,9.48,13.25,12.45,21.72,2.96,8.47,4.45,17.87,4.45,28.2Zm-17.53,0c0-16.43-3.81-29.51-11.43-39.25-7.62-9.74-17.96-14.61-31-14.61s-23.37,4.87-31,14.61c-7.62,9.74-11.43,22.83-11.43,39.25s3.81,29.47,11.43,39.13c7.62,9.65,17.95,14.48,31,14.48s23.38-4.83,31-14.48,11.43-22.69,11.43-39.13Z"/>
373+ </g>
374+ <g>
375+ <rect fill="#e95420" x="0" y="0" width="254.06" height="400"/>
376+ <rect fill="#e95420" x="30.25" y="169.38" width="193.57" height="193.57"/>
377+ <circle fill="white" cx="58.09" cy="255.92" r="26.3"/>
378+ <circle fill="white" cx="167.63" cy="198.25" r="26.3"/>
379+ <path fill="white" d="m117.41,323.61c-18.95-4.06-34.78-16.16-43.68-33.32-7.01,3.19-14.9,4.16-22.49,2.76,10.77,26.45,33.61,45.66,61.65,51.67,6.15,1.32,12.42,1.96,18.68,1.92-4.83-6.35-7.52-14.01-7.7-21.99-2.17-.24-4.33-.59-6.45-1.05Z"/>
380+ <circle fill="white" cx="161.71" cy="323.76" r="26.3"/>
381+ <path fill="white" d="m198.31,314.1c8.18-10.31,13.94-22.5,16.71-35.45,4.84-22.59.32-46.29-12.4-65.51-3.03,7.14-8.17,13.17-14.79,17.32,7.1,13.38,9.26,28.82,6.08,43.67-1.56,7.27-4.31,14.12-8.18,20.38,6.19,5.08,10.56,11.91,12.59,19.6Z"/>
382+ <path fill="white" d="m56.06,218.2c.67-.04,1.34-.05,2-.05,2.66,0,5.31.28,7.94.85,4.29.92,8.32,2.54,12.01,4.84,11.84-17.03,30.95-27.25,51.65-27.63.11-1.99.38-3.97.79-5.92,1.21-5.63,3.67-10.9,7.19-15.41-33.08-2.62-65.22,14.45-81.59,43.33Z"/>
383+ </g>
384+</svg>
385+>>>>>>> data/ubuntu-pro-logo.svg
386diff --git a/debian/changelog b/debian/changelog
387index af14a7c..e284ee7 100644
388--- a/debian/changelog
389+++ b/debian/changelog
390@@ -1,3 +1,4 @@
391+<<<<<<< debian/changelog
392 software-properties (0.99.40) noble; urgency=medium
393
394 * cloudarchive: Enable support for the Caracal Ubuntu Cloud Archive on
395@@ -283,12 +284,28 @@ software-properties (0.99.4) hirsute; urgency=medium
396 -- Corey Bryant <corey.bryant@canonical.com> Tue, 03 Nov 2020 08:58:47 -0500
397
398 software-properties (0.99.3) groovy; urgency=medium
399+=======
400+software-properties (0.96.20.12) xenial; urgency=medium
401+
402+ * Fix invalid syntax for old Python and unused import.
403+
404+ -- Nathan Pratta Teodosio <nathan.teodosio@canonical.com> Wed, 15 Nov 2023 15:24:09 +0100
405+
406+software-properties (0.96.20.11) xenial; urgency=medium
407+
408+ * Backport of the Ubuntu Pro tab (lp: #2029473)
409+
410+ -- Nathan Pratta Teodosio <nathan.teodosio@canonical.com> Wed, 30 Aug 2023 11:29:36 +0200
411+
412+software-properties (0.96.20.10) xenial-security; urgency=medium
413+>>>>>>> debian/changelog
414
415 * SECURITY UPDATE: malicious repo could send ANSI sequences to terminal
416 (LP: #1890286)
417 - add-apt-repository: strip ANSI sequences from the description.
418 - CVE-2020-15709
419
420+<<<<<<< debian/changelog
421 -- Marc Deslauriers <marc.deslauriers@ubuntu.com> Mon, 17 Aug 2020 10:19:34 -0400
422
423 software-properties (0.99.2) groovy; urgency=medium
424@@ -374,10 +391,16 @@ software-properties (0.98.6) focal; urgency=medium
425 -- Corey Bryant <corey.bryant@canonical.com> Wed, 13 Nov 2019 16:00:59 -0500
426
427 software-properties (0.98.5) eoan; urgency=medium
428+=======
429+ -- Marc Deslauriers <marc.deslauriers@ubuntu.com> Fri, 07 Aug 2020 10:08:35 -0400
430+
431+software-properties (0.96.20.9) xenial; urgency=medium
432+>>>>>>> debian/changelog
433
434 * cloudarchive: Update outdated WEB_LINK that is presented when
435 cloud archive is enabled (LP: #1836258).
436
437+<<<<<<< debian/changelog
438 -- Corey Bryant <corey.bryant@canonical.com> Fri, 12 Jul 2019 10:02:43 -0400
439
440 software-properties (0.98.4) eoan; urgency=medium
441@@ -546,10 +569,16 @@ software-properties (0.96.30) disco; urgency=medium
442 -- Sebastien Bacher <seb128@ubuntu.com> Tue, 15 Jan 2019 10:48:27 +0100
443
444 software-properties (0.96.29) disco; urgency=medium
445+=======
446+ -- Corey Bryant <corey.bryant@canonical.com> Fri, 12 Jul 2019 10:15:23 -0400
447+
448+software-properties (0.96.20.8) xenial; urgency=medium
449+>>>>>>> debian/changelog
450
451 * SoftwarePropertiesGtk.py: when checking a package's depends for DKMS also
452 pass on an AttributeError (LP: #1807373)
453
454+<<<<<<< debian/changelog
455 -- Brian Murray <brian@ubuntu.com> Tue, 11 Dec 2018 14:35:40 -0800
456
457 software-properties (0.96.28) disco; urgency=medium
458@@ -863,18 +892,45 @@ software-properties (0.96.24.10) zesty; urgency=medium
459
460 software-properties (0.96.24.9) zesty; urgency=medium
461
462+=======
463+ -- Brian Murray <brian@ubuntu.com> Mon, 17 Dec 2018 11:21:26 -0800
464+
465+software-properties (0.96.20.7) xenial; urgency=medium
466+
467+ * software-properties-gtk:
468+ - fix the backend code to set the gnome debconf frontend, without which
469+ libgtk2-perl goes unused.
470+ - depend on libgtk2-perl to ensure it's available, since it was not seeded
471+ on the desktop at release time. This is only a Recommends: in zesty,
472+ but we need to ensure this isn't ignored on upgrade.
473+ LP: #1679784.
474+
475+ -- Steve Langasek <steve.langasek@ubuntu.com> Thu, 27 Apr 2017 16:21:42 -0700
476+
477+software-properties (0.96.20.6) xenial; urgency=medium
478+
479+ * Add knowledge of OpenStack releases Pike and Queens. (LP: #1670385)
480+
481+>>>>>>> debian/changelog
482 [ Scott Moser & Dimitri John Ledkov ]
483 * When failing to retrieve a GPG key, raise an exception such that
484 e.g. add-apt-repository can fail when it did not manage to retrieve a
485 GPG key for the shortcut repository. LP: #1532855
486
487+<<<<<<< debian/changelog
488 -- Dimitri John Ledkov <xnox@ubuntu.com> Wed, 01 Mar 2017 17:38:45 +0000
489
490 software-properties (0.96.24.8) zesty; urgency=medium
491+=======
492+ -- Scott Moser <smoser@ubuntu.com> Mon, 06 Mar 2017 16:56:40 -0500
493+
494+software-properties (0.96.20.5) xenial; urgency=medium
495+>>>>>>> debian/changelog
496
497 * cloudarchive: Enable support for the Ocata Ubuntu Cloud Archive on
498 16.04 (LP: #1645827).
499
500+<<<<<<< debian/changelog
501 -- Corey Bryant <corey.bryant@canonical.com> Tue, 29 Nov 2016 13:29:35 -0500
502
503 software-properties (0.96.24.7) yakkety; urgency=medium
504@@ -935,6 +991,11 @@ software-properties (0.96.24.3) yakkety; urgency=medium
505 -- Sebastien Bacher <seb128@ubuntu.com> Wed, 17 Aug 2016 11:34:26 +0200
506
507 software-properties (0.96.24.2) yakkety; urgency=medium
508+=======
509+ -- Corey Bryant <corey.bryant@canonical.com> Tue, 29 Nov 2016 13:49:16 -0500
510+
511+software-properties (0.96.20.4) xenial; urgency=medium
512+>>>>>>> debian/changelog
513
514 * Do not assume that a distribution adding the PPA of another distribution
515 will want the latest series all the time. Instead check if the requested
516@@ -944,6 +1005,7 @@ software-properties (0.96.24.2) yakkety; urgency=medium
517 use the same series name. As long as launchpad knows about the series we
518 should be fine even if the constraints are a bit lax.
519
520+<<<<<<< debian/changelog
521 -- Harald Sitter <sitter@kde.org> Fri, 12 Aug 2016 13:52:41 +0200
522
523 software-properties (0.96.24.1) yakkety; urgency=medium
524@@ -959,6 +1021,11 @@ software-properties (0.96.24) yakkety; urgency=medium
525 -- Brian Murray <brian@ubuntu.com> Thu, 23 Jun 2016 10:33:47 -0700
526
527 software-properties (0.96.23) yakkety; urgency=medium
528+=======
529+ -- Harald Sitter <sitter@kde.org> Fri, 12 Aug 2016 16:12:07 +0200
530+
531+software-properties (0.96.20.3) xenial; urgency=medium
532+>>>>>>> debian/changelog
533
534 * softwareproperties/ppa.py:
535 - fix exception output when `add-apt-repository` is called with
536@@ -967,23 +1034,39 @@ software-properties (0.96.23) yakkety; urgency=medium
537 - add network check for tests that require talking to launchpad
538 or the cloud archives
539
540+<<<<<<< debian/changelog
541 -- Michael Vogt <michael.vogt@ubuntu.com> Wed, 22 Jun 2016 15:42:14 +0200
542
543 software-properties (0.96.22) yakkety; urgency=medium
544+=======
545+ -- Brian Murray <brian@ubuntu.com> Fri, 22 Jul 2016 15:27:26 -0700
546+
547+software-properties (0.96.20.2) xenial; urgency=medium
548+>>>>>>> debian/changelog
549
550 * SoftwarePropertiesGtk.py: only add mirror choices if there are mirrors
551 available from which to choose. (LP: #1101881)
552 * DialogMirror.py: guard against a traceback when get cursor returns None.
553 (LP: #1101881)
554
555+<<<<<<< debian/changelog
556 -- Brian Murray <brian@ubuntu.com> Mon, 20 Jun 2016 11:08:28 -0700
557
558 software-properties (0.96.21) yakkety; urgency=medium
559+=======
560+ -- Brian Murray <brian@ubuntu.com> Tue, 21 Jun 2016 12:22:08 -0700
561+
562+software-properties (0.96.20.1) xenial; urgency=medium
563+>>>>>>> debian/changelog
564
565 * cloudarchive: Enable support for the Newton Ubuntu Cloud Archive on
566 16.04 (LP: #1591382).
567
568+<<<<<<< debian/changelog
569 -- Corey Bryant <corey.bryant@canonical.com> Fri, 10 Jun 2016 17:22:43 -0400
570+=======
571+ -- Corey Bryant <corey.bryant@canonical.com> Fri, 10 Jun 2016 17:32:35 -0400
572+>>>>>>> debian/changelog
573
574 software-properties (0.96.20) xenial; urgency=medium
575
576diff --git a/debian/control b/debian/control
577index fcb6123..4690b5b 100644
578--- a/debian/control
579+++ b/debian/control
580@@ -33,6 +33,7 @@ XS-Testsuite: autopkgtest
581 Package: python3-software-properties
582 Section: python
583 Architecture: all
584+<<<<<<< debian/control
585 Depends: gpg,
586 iso-codes,
587 lsb-release,
588@@ -42,6 +43,12 @@ Depends: gpg,
589 python3-launchpadlib,
590 ${misc:Depends},
591 ${python3:Depends}
592+=======
593+Depends: ${python3:Depends}, ${misc:Depends}, python3, python3-apt (>=
594+ 0.6.20ubuntu16), python3-pycurl, lsb-release, iso-codes, python3-distro-info
595+ (>= 0.14ubuntu0.3), ubuntu-advantage-tools (>=27.11~),
596+ ubuntu-advantage-desktop-daemon
597+>>>>>>> debian/control
598 Recommends: unattended-upgrades
599 Description: manage the repositories that you install software from
600 This software provides an abstraction of the used apt repositories.
601@@ -75,6 +82,7 @@ Description: manage the repositories that you install software from (common)
602
603 Package: software-properties-gtk
604 Architecture: all
605+<<<<<<< debian/control
606 Depends: gir1.2-goa-1.0 (>= 3.27.92-1ubuntu1),
607 gir1.2-gtk-3.0,
608 gir1.2-handy-1,
609@@ -92,6 +100,17 @@ Depends: gir1.2-goa-1.0 (>= 3.27.92-1ubuntu1),
610 ${python3:Depends}
611 Recommends: gnome-keyring,
612 gnome-session-bin | xfce4-session | mate-session-manager
613+=======
614+Depends: ${python3:Depends}, ${misc:Depends}, python3,
615+ python3-software-properties (= ${binary:Version}),
616+ python3-gi,
617+ gir1.2-gtk-3.0,
618+ python3-aptdaemon.gtk3widgets,
619+ software-properties-common,
620+ ubuntu-drivers-common (>= 1:0.2.75),
621+ python3-gi,
622+ libgtk2-perl,
623+>>>>>>> debian/control
624 Description: manage the repositories that you install software from (gtk)
625 This software provides an abstraction of the used apt repositories.
626 It allows you to easily manage your distribution and independent software
627diff --git a/debian/software-properties-gtk.install b/debian/software-properties-gtk.install
628index be53144..fbaac36 100644
629--- a/debian/software-properties-gtk.install
630+++ b/debian/software-properties-gtk.install
631@@ -2,6 +2,7 @@
632 debian/tmp/usr/bin/software-properties-gtk
633 debian/tmp/usr/lib/python3*/*-packages/softwareproperties/gtk/*.py
634 debian/tmp/usr/share/applications/software-properties-drivers.desktop
635+<<<<<<< debian/software-properties-gtk.install
636 debian/tmp/usr/share/applications/software-properties-gtk.desktop
637 debian/tmp/usr/share/applications/software-properties-livepatch.desktop
638 debian/tmp/usr/share/glib-2.0/schemas
639@@ -11,3 +12,7 @@ debian/tmp/usr/share/mime/packages
640 debian/tmp/usr/share/software-properties/gtkbuilder
641 debian/tmp/usr/share/software-properties/ubuntu-pro-logo.svg
642 debian/tmp/usr/share/software-properties/ubuntu-pro-logo-dark.svg
643+=======
644+debian/tmp/usr/share/software-properties/ubuntu-pro-logo.svg
645+#debian/tmp/usr/share/gnome/help/software-properties
646+>>>>>>> debian/software-properties-gtk.install
647diff --git a/po/POTFILES.in b/po/POTFILES.in
648index 97ce1bf..ff745a1 100644
649--- a/po/POTFILES.in
650+++ b/po/POTFILES.in
651@@ -54,3 +54,7 @@ softwareproperties/sourceslist.py
652 [type: gettext/glade]data/gtkbuilder/dialog-ua-attach.ui
653 [type: gettext/glade]data/gtkbuilder/dialog-ua-detach.ui
654 [type: gettext/glade]data/gtkbuilder/dialog-ua-fips-enable.ui
655+<<<<<<< po/POTFILES.in
656+=======
657+
658+>>>>>>> po/POTFILES.in
659diff --git a/softwareproperties/SoftwareProperties.py b/softwareproperties/SoftwareProperties.py
660index d8f7435..d901f54 100644
661--- a/softwareproperties/SoftwareProperties.py
662+++ b/softwareproperties/SoftwareProperties.py
663@@ -128,7 +128,8 @@ class SoftwareProperties(object):
664 " wait for all running threads (PPA key fetchers) to exit "
665 for t in threading.enumerate():
666 if t.ident != threading.current_thread().ident:
667- t.join()
668+ if not t.daemon:
669+ t.join()
670
671 def backup_apt_conf(self):
672 """Backup all apt configuration options"""
673@@ -682,8 +683,29 @@ class SoftwareProperties(object):
674 if channel:
675 keyp = "%s/%s.key" % (self.CHANNEL_PATH, channel)
676 self.add_key(keyp)
677+<<<<<<< softwareproperties/SoftwareProperties.py
678 return True
679 return False
680+=======
681+
682+ cdata = (shortcut.add_key, {'keyserver': (self.options and
683+ self.options.keyserver)})
684+ def addkey_func():
685+ func, kwargs = cdata
686+ msg = "Added key."
687+ try:
688+ ret = func(**kwargs)
689+ if not ret:
690+ msg = "Failed to add key."
691+ except Exception as e:
692+ ret = False
693+ msg = str(e)
694+ self.myqueue.put([ret, msg])
695+
696+ worker = threading.Thread(target=addkey_func)
697+ worker.start()
698+ return worker
699+>>>>>>> softwareproperties/SoftwareProperties.py
700
701 def update_interface(self):
702 " abstract interface to keep the UI alive "
703@@ -748,6 +770,19 @@ class SoftwareProperties(object):
704 file=new_debsrc_entry.file,
705 architectures=new_debsrc_entry.architectures)
706 self.set_modified_sourceslist()
707+<<<<<<< softwareproperties/SoftwareProperties.py
708+=======
709+ if worker:
710+ # wait for GPG key to be downloaded
711+ worker.join(30)
712+ if worker.isAlive():
713+ # thread timed out.
714+ raise shortcuts.ShortcutException("Error: retrieving gpg key timed out.")
715+ result, msg = self.myqueue.get()
716+ if not result:
717+ raise shortcuts.ShortcutException(msg)
718+
719+>>>>>>> softwareproperties/SoftwareProperties.py
720 if self.options and self.options.update:
721 import apt
722 cache = apt.Cache()
723diff --git a/softwareproperties/cloudarchive.py b/softwareproperties/cloudarchive.py
724index 3cbc5f3..ebeabdf 100644
725--- a/softwareproperties/cloudarchive.py
726+++ b/softwareproperties/cloudarchive.py
727@@ -45,6 +45,7 @@ RELEASE_MAP = {
728 'ocata': 'xenial',
729 'pike': 'xenial',
730 'queens': 'xenial',
731+<<<<<<< softwareproperties/cloudarchive.py
732 'rocky': 'bionic',
733 'stein': 'bionic',
734 'train': 'bionic',
735@@ -57,9 +58,12 @@ RELEASE_MAP = {
736 'antelope': 'jammy',
737 'bobcat': 'jammy',
738 'caracal': 'jammy',
739+=======
740+>>>>>>> softwareproperties/cloudarchive.py
741 }
742 UCA = "Ubuntu Cloud Archive"
743 WEB_LINK = 'https://wiki.ubuntu.com/OpenStack/CloudArchive'
744+<<<<<<< softwareproperties/cloudarchive.py
745
746 UCA_ARCHIVE = "http://ubuntu-cloud.archive.canonical.com/ubuntu"
747 UCA_PREFIXES = ['cloud-archive', 'uca']
748@@ -93,6 +97,23 @@ class CloudArchiveShortcutHandler(ShortcutHandler):
749 if not self.caname in RELEASE_MAP:
750 msg = (_("not a valid cloud-archive: '%s'") % self.caname)
751 raise ShortcutException(msg)
752+=======
753+APT_INSTALL_KEY = ['apt-get', '--quiet', '--assume-yes', 'install',
754+ 'ubuntu-cloud-keyring']
755+
756+ALIASES = {'tools-updates': 'tools'}
757+for _r in RELEASE_MAP:
758+ ALIASES["%s-updates" % _r] = _r
759+
760+MAP = {
761+ 'tools': {
762+ 'sldfmt': '%(codename)s-updates/cloud-tools',
763+ 'description': UCA + " for cloud-tools (JuJu and MAAS)"},
764+ 'tools-proposed': {
765+ 'sldfmt': '%(codename)s-proposed/cloud-tools',
766+ 'description': UCA + " for cloud-tools (JuJu and MAAS) [proposed]"}
767+}
768+>>>>>>> softwareproperties/cloudarchive.py
769
770 codename = RELEASE_MAP[self.caname]
771 validnames = set((codename, os.getenv("CA_ALLOW_CODENAME") or codename))
772diff --git a/softwareproperties/gtk/DialogUaAttach.py b/softwareproperties/gtk/DialogUaAttach.py
773index d029e64..84d93dc 100644
774--- a/softwareproperties/gtk/DialogUaAttach.py
775+++ b/softwareproperties/gtk/DialogUaAttach.py
776@@ -25,6 +25,10 @@ from softwareproperties.gtk.utils import setup_ui
777 from uaclient.api.u.pro.attach.magic.initiate.v1 import initiate
778 from uaclient.api.u.pro.attach.magic.wait.v1 import MagicAttachWaitOptions, wait
779 from uaclient.exceptions import MagicAttachTokenError
780+<<<<<<< softwareproperties/gtk/DialogUaAttach.py
781+=======
782+import threading
783+>>>>>>> softwareproperties/gtk/DialogUaAttach.py
784
785 class DialogUaAttach:
786 def __init__(self, parent, datadir, ua_object):
787@@ -139,8 +143,11 @@ class DialogUaAttach:
788 self.attach()
789
790 def on_cancel_clicked(self, button):
791+<<<<<<< softwareproperties/gtk/DialogUaAttach.py
792 if self.poll:
793 GLib.Thread.unref(self.poll)
794+=======
795+>>>>>>> softwareproperties/gtk/DialogUaAttach.py
796 self.dialog.response(Gtk.ResponseType.CANCEL)
797
798 def poll_for_magic_token(self):
799@@ -148,6 +155,7 @@ class DialogUaAttach:
800 try:
801 response = wait(options)
802 self.contract_token = response.contract_token
803+<<<<<<< softwareproperties/gtk/DialogUaAttach.py
804 if self.magic_radio.get_active():
805 GLib.idle_add(self.update_state, "pin_validated")
806 except MagicAttachTokenError:
807@@ -155,6 +163,13 @@ class DialogUaAttach:
808 GLib.idle_add(self.update_state, "expired")
809 except Exception as e:
810 print("Error getting the Ubuntu Pro token: ", e, flush = True)
811+=======
812+ GLib.idle_add(self.update_state, 'pin_validated')
813+ except MagicAttachTokenError:
814+ GLib.idle_add(self.update_state, 'expired')
815+ except Exception as e:
816+ print("Error getting the Ubuntu Pro token: ", e)
817+>>>>>>> softwareproperties/gtk/DialogUaAttach.py
818 finally:
819 self.poll = None
820
821@@ -163,6 +178,11 @@ class DialogUaAttach:
822 if self.poll != None or self.contract_token != None:
823 return
824
825+<<<<<<< softwareproperties/gtk/DialogUaAttach.py
826+=======
827+ self.contract_token = None
828+
829+>>>>>>> softwareproperties/gtk/DialogUaAttach.py
830 # Request a magic attachment and parse relevants fields from response.
831 # userCode: The pin the user has to type in <ubuntu.com/pro/attach>;
832 # token: Identifies the request (used for polling for it).
833@@ -174,6 +194,7 @@ class DialogUaAttach:
834 print("Error retrieving magic token: ", e)
835 return
836 self.update_state()
837+<<<<<<< softwareproperties/gtk/DialogUaAttach.py
838 self.poll = GLib.Thread.new("poll", self.poll_for_magic_token)
839
840 def on_radio_toggled(self, button):
841@@ -181,6 +202,13 @@ class DialogUaAttach:
842 self.update_state("pin_validated")
843 else:
844 self.update_state()
845+=======
846+ self.poll = threading.Thread(target=self.poll_for_magic_token, daemon=True)
847+ self.poll.start()
848+
849+ def on_radio_toggled(self, button):
850+ self.update_state()
851+>>>>>>> softwareproperties/gtk/DialogUaAttach.py
852
853 def on_magic_radio_clicked(self, button):
854 self.start_magic_attach()
855@@ -197,7 +225,12 @@ class DialogUaAttach:
856 self.start_magic_attach()
857 elif self.poll == None:
858 # wait() timed out without internet; Restart polling.
859+<<<<<<< softwareproperties/gtk/DialogUaAttach.py
860 self.poll = GLib.Thread.new("poll", self.poll_for_magic_token)
861+=======
862+ self.poll = threading.Thread(target=self.poll_for_magic_token, daemon=True)
863+ self.poll.start()
864+>>>>>>> softwareproperties/gtk/DialogUaAttach.py
865
866 def finish(self):
867 self.dialog.response(Gtk.ResponseType.OK)
868diff --git a/softwareproperties/gtk/SoftwarePropertiesGtk.py b/softwareproperties/gtk/SoftwarePropertiesGtk.py
869index 0cced00..847f3dc 100644
870--- a/softwareproperties/gtk/SoftwarePropertiesGtk.py
871+++ b/softwareproperties/gtk/SoftwarePropertiesGtk.py
872@@ -46,7 +46,13 @@ gi.require_version("PackageKitGlib", "1.0")
873 from gi.repository import PackageKitGlib as packagekit
874 from gi.repository import GObject, Gdk, Gtk, Gio, GLib, Handy
875
876+<<<<<<< softwareproperties/gtk/SoftwarePropertiesGtk.py
877 from aptsources.sourceslist import Deb822SourceEntry
878+=======
879+import gi
880+gi.require_version("Gdk", "3.0")
881+from gi.repository import GObject, Gdk, Gtk, Gio, GLib
882+>>>>>>> softwareproperties/gtk/SoftwarePropertiesGtk.py
883
884 from .SimpleGtkbuilderApp import SimpleGtkbuilderApp
885 from .DialogAdd import DialogAdd
886@@ -252,9 +258,14 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp):
887 self.show_distro()
888 # Setup and show the Additonal Drivers tab
889 self.init_drivers()
890+<<<<<<< softwareproperties/gtk/SoftwarePropertiesGtk.py
891 # Setup and show the Ubuntu Pro tab if the serie is a LTS
892 if is_current_distro_lts():
893 self.init_ubuntu_pro()
894+=======
895+ # Setup and show the Ubuntu Pro tab
896+ self.init_ubuntu_pro()
897+>>>>>>> softwareproperties/gtk/SoftwarePropertiesGtk.py
898
899 # Connect to switch-page before setting initial tab. Otherwise the
900 # first switch goes unnoticed.
901@@ -489,6 +500,57 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp):
902 self.handlers[combobox] = combobox.connect(
903 "changed", self.on_combobox_updates_subscription_changed)
904
905+ status = get_ua_status()
906+ if not is_current_distro_lts():
907+ esm_available = False
908+ esm_enabled = False
909+ else:
910+ (infra_available, infra_status) = get_ua_service_status("esm-infra", status=status)
911+ (apps_available, apps_status) = get_ua_service_status("esm-apps", status=status)
912+ esm_available = bool(infra_available or apps_available)
913+ esm_enabled = "enabled" in (infra_status, apps_status)
914+ distro = current_distro()
915+ if esm_enabled:
916+ eol_text = _("Extended Security Maintenance")
917+ # EOL date should probably be UA contract expiry.
918+ # This is probably sooner than ESM EOL for the distro and
919+ # gives software properties dialogs a chance to interact about
920+ # renewals if needed.
921+ try:
922+ # Ignore timezone to simplify formatting python < 3.7
923+ # 3.7 has datetime.fromisoformat()
924+ dt, _sep, _tz = status.get("expires", "").partition("+")
925+ eol_date = datetime.datetime.strptime(
926+ dt, "%Y-%m-%dT%H:%M:%S"
927+ ).date()
928+ except ValueError:
929+ print("Unable to determine UA contract expiry")
930+ eol_date = distro.eol
931+ else:
932+ eol_text = _("Basic Security Maintenance")
933+ eol_date = distro.eol
934+ self.label_esm_status.set_markup(eol_text)
935+ esm_url = "https://ubuntu.com/esm" # Non-EOL LTS generic ESM
936+ today = datetime.datetime.now().date()
937+ if today >= eol_date:
938+ if esm_available:
939+ # EOL LTS uses release-specific ESM ubuntu.com/XX-YY
940+ distro_ver = distro.version.replace(' LTS', '')
941+ esm_url = "https://ubuntu.com/%s" % distro_ver.replace(".", "-")
942+ eol_expiry_text = _("Ended %s - extend or upgrade now") % eol_date.strftime("%x")
943+ elif today >= eol_date - datetime.timedelta(days=60):
944+ eol_expiry_text = _("Ends %s - extend or upgrade soon") % eol_date.strftime("%x")
945+ else:
946+ eol_expiry_text = _("Active until %s") % eol_date.strftime("%x")
947+ self.label_eol.set_label(eol_expiry_text)
948+ self.label_esm_subscribe.set_markup(
949+ "<a href=\"%s\">%s</a>" % (esm_url, _("Extend…"))
950+ )
951+ self.label_esm_subscribe.set_visible(
952+ esm_available and not esm_enabled
953+ )
954+ eol_expiry_text = _("Ended %s") % eol_date.strftime("%x")
955+
956 # setup the server chooser
957 cell = Gtk.CellRendererText()
958 self.combobox_server.pack_start(cell, True)
959@@ -1281,6 +1343,7 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp):
960
961 self.cancellable = Gio.Cancellable()
962 try:
963+<<<<<<< softwareproperties/gtk/SoftwarePropertiesGtk.py
964 if removals:
965 installs_pending = False
966 if installs:
967@@ -1308,6 +1371,16 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp):
968 False # ready data
969 )
970
971+=======
972+ self.transaction = self.apt_client.commit_packages(install=installs, remove=removals,
973+ reinstall=[], purge=[], upgrade=[], downgrade=[])
974+ self.transaction.connect("progress-changed", self.on_driver_changes_progress)
975+ self.transaction.connect("cancellable-changed", self.on_driver_changes_cancellable_changed)
976+ self.transaction.connect("finished", self.on_driver_changes_finish)
977+ self.transaction.connect("error", self.on_driver_changes_error)
978+ self.transaction.set_debconf_frontend("gnome")
979+ self.transaction.run()
980+>>>>>>> softwareproperties/gtk/SoftwarePropertiesGtk.py
981 self.button_driver_revert.set_sensitive(False)
982 self.button_driver_apply.set_sensitive(False)
983 self.scrolled_window_drivers.set_sensitive(False)
984@@ -1425,6 +1498,7 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp):
985 return
986
987 pkg = None
988+<<<<<<< softwareproperties/gtk/SoftwarePropertiesGtk.py
989 if pkg_name:
990 pkg = self.apt_cache[pkg_name]
991 # Add the matching linux modules package when available
992@@ -1435,6 +1509,24 @@ class SoftwarePropertiesGtk(SoftwareProperties, SimpleGtkbuilderApp):
993 self.driver_changes.append(modules_package_obj)
994 except (KeyError, TypeError):
995 pass
996+=======
997+ try:
998+ if pkg_name:
999+ pkg = self.apt_cache[pkg_name]
1000+ # If the package depends on dkms
1001+ # we need to install the correct linux metapackage
1002+ # so that users get the latest headers
1003+ if 'dkms' in pkg.candidate.record['Depends']:
1004+ linux_meta = detect.get_linux(self.apt_cache)
1005+ if (linux_meta and
1006+ linux_meta not in self.driver_changes):
1007+ # Install the linux metapackage
1008+ lmp = self.apt_cache[linux_meta]
1009+ if not lmp.is_installed:
1010+ self.driver_changes.append(lmp)
1011+ except (AttributeError, KeyError):
1012+ pass
1013+>>>>>>> softwareproperties/gtk/SoftwarePropertiesGtk.py
1014
1015 if button.get_active():
1016 if pkg in self.driver_changes:
1017diff --git a/softwareproperties/gtk/UbuntuProPage.py b/softwareproperties/gtk/UbuntuProPage.py
1018index 113fed0..4cf4cf4 100644
1019--- a/softwareproperties/gtk/UbuntuProPage.py
1020+++ b/softwareproperties/gtk/UbuntuProPage.py
1021@@ -22,7 +22,11 @@ from gettext import gettext as _
1022 import gi
1023 gi.require_version("Gtk", "3.0")
1024 from gi.repository import GdkPixbuf, Gio, Gtk
1025+<<<<<<< softwareproperties/gtk/UbuntuProPage.py
1026 from softwareproperties.gtk.utils import current_distro, is_dark_theme
1027+=======
1028+from softwareproperties.gtk.utils import current_distro
1029+>>>>>>> softwareproperties/gtk/UbuntuProPage.py
1030
1031 from .DialogUaAttach import DialogUaAttach
1032 from .DialogUaDetach import DialogUaDetach
1033@@ -77,6 +81,7 @@ class UbuntuProPage(object):
1034 self.label_ua_usg_status = parent.label_ua_usg_status
1035 self.label_ua_usg_description = parent.label_ua_usg_description
1036
1037+<<<<<<< softwareproperties/gtk/UbuntuProPage.py
1038 if is_dark_theme(self.stack_ua_attach):
1039 ubuntu_pro_logo = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(parent.datadir, 'ubuntu-pro-logo-dark.svg'), -1, 50, True)
1040 else:
1041@@ -86,6 +91,11 @@ class UbuntuProPage(object):
1042 # Display the tab on init which is only on LTS series
1043 self.stack_ua_main.set_visible(True)
1044
1045+=======
1046+ ubuntu_pro_logo = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(parent.datadir, 'ubuntu-pro-logo.svg'), -1, 50, True)
1047+ parent.image_ubuntu_pro_logo.set_from_pixbuf(ubuntu_pro_logo)
1048+
1049+>>>>>>> softwareproperties/gtk/UbuntuProPage.py
1050 parent.button_ua_attach.connect('clicked', self.on_button_ua_attach_clicked)
1051 parent.button_ua_detach.connect('clicked', self.on_button_ua_detach_clicked)
1052 self.on_ua_esm_infra_changed_handler = self.switch_ua_esm_infra.connect('notify::active', self.on_ua_esm_infra_changed)
1053diff --git a/softwareproperties/gtk/utils.py b/softwareproperties/gtk/utils.py
1054index 6f67f33..d7c7995 100644
1055--- a/softwareproperties/gtk/utils.py
1056+++ b/softwareproperties/gtk/utils.py
1057@@ -28,11 +28,24 @@ import json
1058 import os
1059 import subprocess
1060
1061+<<<<<<< softwareproperties/gtk/utils.py
1062 import logging
1063 LOG=logging.getLogger(__name__)
1064
1065 import time
1066
1067+=======
1068+from gi.repository import Gtk
1069+import aptsources.distro
1070+import distro_info
1071+import json
1072+import os
1073+import subprocess
1074+
1075+import logging
1076+LOG=logging.getLogger(__name__)
1077+
1078+>>>>>>> softwareproperties/gtk/utils.py
1079 UA_STATUS_JSON = "/var/lib/ubuntu-advantage/status.json"
1080
1081 def setup_ui(self, path, domain):
1082@@ -47,6 +60,7 @@ def setup_ui(self, path, domain):
1083 setattr(self, name, o)
1084 else:
1085 logging.debug("can not get name for object '%s'" % o)
1086+<<<<<<< softwareproperties/gtk/utils.py
1087
1088 def has_gnome_online_accounts():
1089 try:
1090@@ -55,16 +69,21 @@ def has_gnome_online_accounts():
1091 except Exception:
1092 return False
1093
1094+=======
1095+>>>>>>> softwareproperties/gtk/utils.py
1096 def is_current_distro_lts():
1097 distro = aptsources.distro.get_distro()
1098 di = distro_info.UbuntuDistroInfo()
1099 return di.is_lts(distro.codename)
1100
1101+<<<<<<< softwareproperties/gtk/utils.py
1102 def is_current_distro_supported():
1103 distro = aptsources.distro.get_distro()
1104 di = distro_info.UbuntuDistroInfo()
1105 return distro.codename in di.supported(datetime.now().date())
1106
1107+=======
1108+>>>>>>> softwareproperties/gtk/utils.py
1109 def current_distro():
1110 distro = aptsources.distro.get_distro()
1111 di = distro_info.UbuntuDistroInfo()
1112@@ -100,7 +119,12 @@ def get_ua_status():
1113 "Ubuntu Advantage client returned code %d" % result.returncode
1114 )
1115 return {}
1116+<<<<<<< softwareproperties/gtk/utils.py
1117 status_json = result.stdout
1118+=======
1119+ # result.stdout is type bytes, but json.loads only accepts str in <3.6.
1120+ status_json = result.stdout.decode('utf-8')
1121+>>>>>>> softwareproperties/gtk/utils.py
1122 if not status_json:
1123 print(
1124 "Warning: no Ubuntu Advantage status found."
1125@@ -146,6 +170,7 @@ def get_ua_service_status(service_name='esm-infra', status=None):
1126 if "status" in service:
1127 service_status = service["status"] # enabled, disabled or n/a
1128 return (available, service_status)
1129+<<<<<<< softwareproperties/gtk/utils.py
1130
1131
1132 def retry(exceptions, tries=10, delay=0.1, backoff=2):
1133@@ -185,3 +210,5 @@ def is_dark_theme(widget):
1134 if env_gtk_theme != None:
1135 return GLib.str_has_suffix(env_gtk_theme, "dark")
1136 return Handy.StyleManager.get_default().get_dark()
1137+=======
1138+>>>>>>> softwareproperties/gtk/utils.py
1139diff --git a/softwareproperties/ppa.py b/softwareproperties/ppa.py
1140index 4ec6cb2..8b4cfff 100644
1141--- a/softwareproperties/ppa.py
1142+++ b/softwareproperties/ppa.py
1143@@ -25,6 +25,7 @@ from gettext import gettext as _
1144 from launchpadlib.launchpad import Launchpad
1145 from lazr.restfulclient.errors import (NotFound, BadRequest, Unauthorized)
1146
1147+<<<<<<< softwareproperties/ppa.py
1148 from softwareproperties.shortcuthandler import (ShortcutHandler, ShortcutException,
1149 InvalidShortcutException)
1150 from softwareproperties.sourceslist import SourcesListShortcutHandler
1151@@ -182,8 +183,208 @@ class PPAShortcutHandler(ShortcutHandler):
1152 def _match_ppa(self, shortcut):
1153 (prefix, _, ppa) = shortcut.rpartition(':')
1154 if not prefix.lower() == 'ppa':
1155+=======
1156+from gettext import gettext as _
1157+from threading import Thread
1158+
1159+from softwareproperties.shortcuts import ShortcutException
1160+
1161+try:
1162+ import urllib.request
1163+ from urllib.error import HTTPError, URLError
1164+ import urllib.parse
1165+ from http.client import HTTPException
1166+ NEED_PYCURL = False
1167+except ImportError:
1168+ NEED_PYCURL = True
1169+ import pycurl
1170+ HTTPError = pycurl.error
1171+
1172+
1173+DEFAULT_KEYSERVER = "hkp://keyserver.ubuntu.com:80/"
1174+# maintained until 2015
1175+LAUNCHPAD_PPA_API = 'https://launchpad.net/api/1.0/%s/+archive/%s'
1176+LAUNCHPAD_USER_API = 'https://launchpad.net/api/1.0/%s'
1177+LAUNCHPAD_USER_PPAS_API = 'https://launchpad.net/api/1.0/%s/ppas'
1178+LAUNCHPAD_DISTRIBUTION_API = 'https://launchpad.net/api/1.0/%s'
1179+LAUNCHPAD_DISTRIBUTION_SERIES_API = 'https://launchpad.net/api/1.0/%s/%s'
1180+# Specify to use the system default SSL store; change to a different path
1181+# to test with custom certificates.
1182+LAUNCHPAD_PPA_CERT = "/etc/ssl/certs/ca-certificates.crt"
1183+
1184+
1185+class CurlCallback:
1186+ def __init__(self):
1187+ self.contents = ''
1188+
1189+ def body_callback(self, buf):
1190+ self.contents = self.contents + buf
1191+
1192+
1193+class PPAException(Exception):
1194+
1195+ def __init__(self, value, original_error=None):
1196+ self.value = value
1197+ self.original_error = original_error
1198+
1199+ def __str__(self):
1200+ return repr(self.value)
1201+
1202+
1203+def encode(s):
1204+ return re.sub("[^a-zA-Z0-9_-]", "_", s)
1205+
1206+def get_info_from_lp(lp_url):
1207+ if NEED_PYCURL:
1208+ # python2 has no cert verification so we need pycurl
1209+ return _get_https_content_pycurl(lp_url)
1210+ else:
1211+ # python3 has cert verification so we can use the buildin urllib
1212+ return _get_https_content_py3(lp_url)
1213+
1214+def get_ppa_info_from_lp(owner_name, ppa):
1215+ lp_url = LAUNCHPAD_PPA_API % (owner_name, ppa)
1216+ return get_info_from_lp(lp_url)
1217+
1218+def series_valid_for_distro(distribution, series):
1219+ lp_url = LAUNCHPAD_DISTRIBUTION_SERIES_API % (distribution, series)
1220+ try:
1221+ get_info_from_lp(lp_url)
1222+ return True
1223+ except PPAException:
1224+ return False
1225+
1226+def get_current_series_from_lp(distribution):
1227+ lp_url = LAUNCHPAD_DISTRIBUTION_API % distribution
1228+ return os.path.basename(get_info_from_lp(lp_url)["current_series_link"])
1229+
1230+
1231+def _get_https_content_py3(lp_url):
1232+ try:
1233+ request = urllib.request.Request(str(lp_url), headers={"Accept":" application/json"})
1234+ lp_page = urllib.request.urlopen(request, cafile=LAUNCHPAD_PPA_CERT)
1235+ json_data = lp_page.read().decode("utf-8", "strict")
1236+ except (URLError, HTTPException) as e:
1237+ # HTTPException doesn't have a reason but might have a string
1238+ # representation
1239+ reason = hasattr(e, "reason") and e.reason or e
1240+ raise PPAException("Error reading %s: %s" % (lp_url, reason), e)
1241+ return json.loads(json_data)
1242+
1243+def _get_https_content_pycurl(lp_url):
1244+ # this is the fallback code for python2
1245+ try:
1246+ callback = CurlCallback()
1247+ curl = pycurl.Curl()
1248+ curl.setopt(pycurl.SSL_VERIFYPEER, 1)
1249+ curl.setopt(pycurl.SSL_VERIFYHOST, 2)
1250+ curl.setopt(pycurl.WRITEFUNCTION, callback.body_callback)
1251+ if LAUNCHPAD_PPA_CERT:
1252+ curl.setopt(pycurl.CAINFO, LAUNCHPAD_PPA_CERT)
1253+ curl.setopt(pycurl.URL, str(lp_url))
1254+ curl.setopt(pycurl.HTTPHEADER, ["Accept: application/json"])
1255+ curl.perform()
1256+ curl.close()
1257+ json_data = callback.contents
1258+ except pycurl.error as e:
1259+ raise PPAException("Error reading %s: %s" % (lp_url, e), e)
1260+ return json.loads(json_data)
1261+
1262+
1263+def mangle_ppa_shortcut(shortcut):
1264+ ppa_shortcut = shortcut.split(":")[1]
1265+ if ppa_shortcut.startswith("/"):
1266+ ppa_shortcut = ppa_shortcut.lstrip("/")
1267+ user = ppa_shortcut.split("/")[0]
1268+ if (user[0] == "~"):
1269+ user = user[1:]
1270+ ppa_path_objs = ppa_shortcut.split("/")[1:]
1271+ ppa_path = []
1272+ if (len(ppa_path_objs) < 1):
1273+ ppa_path = ['ubuntu', 'ppa']
1274+ elif (len(ppa_path_objs) == 1):
1275+ ppa_path.insert(0, "ubuntu")
1276+ ppa_path.extend(ppa_path_objs)
1277+ else:
1278+ ppa_path = ppa_path_objs
1279+ ppa = "~%s/%s" % (user, "/".join(ppa_path))
1280+ return ppa
1281+
1282+def verify_keyid_is_v4(signing_key_fingerprint):
1283+ """Verify that the keyid is a v4 fingerprint with at least 160bit"""
1284+ return len(signing_key_fingerprint) >= 160/8
1285+
1286+
1287+class AddPPASigningKey(object):
1288+ " thread class for adding the signing key in the background "
1289+
1290+ GPG_DEFAULT_OPTIONS = ["gpg", "--no-default-keyring", "--no-options"]
1291+
1292+ def __init__(self, ppa_path, keyserver=None):
1293+ self.ppa_path = ppa_path
1294+ self.keyserver = (keyserver if keyserver is not None
1295+ else DEFAULT_KEYSERVER)
1296+
1297+ def _recv_key(self, keyring, secret_keyring, signing_key_fingerprint, keyring_dir):
1298+ try:
1299+ # double check that the signing key is a v4 fingerprint (160bit)
1300+ if not verify_keyid_is_v4(signing_key_fingerprint):
1301+ print("Error: signing key fingerprint '%s' too short" %
1302+ signing_key_fingerprint)
1303+ return False
1304+ except TypeError:
1305+ print("Error: signing key fingerprint does not exist")
1306 return False
1307+ # then get it
1308+ res = subprocess.call(self.GPG_DEFAULT_OPTIONS + [
1309+ "--homedir", keyring_dir,
1310+ "--secret-keyring", secret_keyring,
1311+ "--keyring", keyring,
1312+ "--keyserver", self.keyserver,
1313+ "--recv", signing_key_fingerprint,
1314+ ])
1315+ return (res == 0)
1316+
1317+ def _export_key(self, keyring, export_keyring, signing_key_fingerprint, keyring_dir):
1318+ res = subprocess.call(self.GPG_DEFAULT_OPTIONS + [
1319+ "--homedir", keyring_dir,
1320+ "--keyring", keyring,
1321+ "--output", export_keyring,
1322+ "--export", signing_key_fingerprint,
1323+ ])
1324+ if res != 0:
1325+ return False
1326+ return True
1327
1328+ def _get_fingerprints(self, keyring, keyring_dir):
1329+ cmd = self.GPG_DEFAULT_OPTIONS + [
1330+ "--homedir", keyring_dir,
1331+ "--keyring", keyring,
1332+ "--fingerprint",
1333+ "--batch",
1334+ "--with-colons",
1335+ ]
1336+ output = subprocess.check_output(cmd, universal_newlines=True)
1337+ fingerprints = []
1338+ for line in output.splitlines():
1339+ if line.startswith("fpr:"):
1340+ fingerprints.append(line.split(":")[9])
1341+ return fingerprints
1342+
1343+ def _verify_fingerprint(self, keyring, expected_fingerprint, keyring_dir):
1344+ got_fingerprints = self._get_fingerprints(keyring, keyring_dir)
1345+ if len(got_fingerprints) > 1:
1346+ print("Got '%s' fingerprints, expected only one" %
1347+ len(got_fingerprints))
1348+ return False
1349+ got_fingerprint = got_fingerprints[0]
1350+ if got_fingerprint != expected_fingerprint:
1351+ print("Fingerprints do not match, not importing: '%s' != '%s'" % (
1352+ expected_fingerprint, got_fingerprint))
1353+>>>>>>> softwareproperties/ppa.py
1354+ return False
1355+
1356+<<<<<<< softwareproperties/ppa.py
1357 (teamname, _, ppaname) = ppa.partition('/')
1358 teamname = teamname.lstrip('~')
1359 if '/' in ppaname:
1360@@ -194,6 +395,16 @@ class PPAShortcutHandler(ShortcutHandler):
1361 if '/' in ppaname:
1362 # Path is too long for valid ppa
1363 return False
1364+=======
1365+ def add_ppa_signing_key(self, ppa_path=None):
1366+ """Query and add the corresponding PPA signing key.
1367+
1368+ The signing key fingerprint is obtained from the Launchpad PPA page,
1369+ via a secure channel, so it can be trusted.
1370+ """
1371+ if ppa_path is None:
1372+ ppa_path = self.ppa_path
1373+>>>>>>> softwareproperties/ppa.py
1374
1375 self.teamname = teamname
1376 self.ppaname = ppaname or 'ppa'
1377@@ -221,8 +432,135 @@ class PPAShortcutHandler(ShortcutHandler):
1378 path = parsed.path.strip().strip('/').split('/')
1379 if len(path) < 2:
1380 return False
1381+<<<<<<< softwareproperties/ppa.py
1382 self.teamname = path[0]
1383 self.ppaname = path[1]
1384+=======
1385+ # and add it
1386+ trustedgpgd = apt_pkg.config.find_dir("Dir::Etc::trustedparts")
1387+ apt_keyring = os.path.join(trustedgpgd, "%s.gpg" % (
1388+ encode(ppa_info["reference"][1:])))
1389+ res = subprocess.call(["apt-key", "--keyring", apt_keyring, "add",
1390+ tmp_keyring])
1391+ # cleanup
1392+ cleanup(tmp_keyring_dir)
1393+ return (res == 0)
1394+
1395+
1396+class AddPPASigningKeyThread(Thread, AddPPASigningKey):
1397+ # This class is legacy. There are no users inside the software-properties
1398+ # codebase other than a test case. It was left in case there were outside
1399+ # users. Internally, we've changed from having a class implement the
1400+ # tread to explicitly launching a thread and invoking a method in it
1401+ # see check_and_add_key_for_whitelisted_shortcut for how.
1402+ def __init__(self, ppa_path, keyserver=None):
1403+ Thread.__init__(self)
1404+ AddPPASigningKey.__init__(self, ppa_path=ppa_path, keyserver=keyserver)
1405+
1406+ def run(self):
1407+ self.add_ppa_signing_key(self.ppa_path)
1408+
1409+
1410+def _get_suggested_ppa_message(user, ppa_name):
1411+ try:
1412+ msg = []
1413+ try:
1414+ try:
1415+ lp_user = get_info_from_lp(LAUNCHPAD_USER_API % user)
1416+ except PPAException:
1417+ return _("ERROR: '{user}' user or team does not exist.").format(user=user)
1418+ lp_ppas = get_info_from_lp(LAUNCHPAD_USER_PPAS_API % user)
1419+ entity_name = _("team") if lp_user["is_team"] else _("user")
1420+ if lp_ppas["total_size"] > 0:
1421+ # Translators: %(entity)s is either "team" or "user"
1422+ msg.append(_("The %(entity)s named '%(user)s' has no PPA named '%(ppa)s'") % {
1423+ 'entity' : entity_name,
1424+ 'user' : user,
1425+ 'ppa' : ppa_name})
1426+ msg.append(_("Please choose from the following available PPAs:"))
1427+ for ppa in lp_ppas["entries"]:
1428+ msg.append(_(" * '%(name)s': %(displayname)s") % {
1429+ 'name' : ppa["name"],
1430+ 'displayname' : ppa["displayname"]})
1431+ else:
1432+ # Translators: %(entity)s is either "team" or "user"
1433+ msg.append(_("The %(entity)s named '%(user)s' does not have any PPA") % {
1434+ 'entity' : entity_name, 'user' : user})
1435+ return '\n'.join(msg)
1436+ except KeyError:
1437+ return ''
1438+ except ImportError:
1439+ return _("Please check that the PPA name or format is correct.")
1440+
1441+
1442+def get_ppa_info(shortcut):
1443+ user = shortcut.split("/")[0]
1444+ ppa = "/".join(shortcut.split("/")[1:])
1445+ try:
1446+ ret = get_ppa_info_from_lp(user, ppa)
1447+ ret["distribution"] = ret["distribution_link"].split('/')[-1]
1448+ ret["owner"] = ret["owner_link"].split('/')[-1]
1449+ return ret
1450+ except (HTTPError, Exception):
1451+ msg = []
1452+ msg.append(_("Cannot add PPA: 'ppa:%s/%s'.") % (
1453+ user, ppa))
1454+
1455+ # If the PPA does not exist, then try to find if the user/team
1456+ # exists. If it exists, list down the PPAs
1457+ raise ShortcutException('\n'.join(msg) + "\n" +
1458+ _get_suggested_ppa_message(user, ppa))
1459+
1460+ except (ValueError, PPAException):
1461+ raise ShortcutException(
1462+ _("Cannot access PPA (%s) to get PPA information, "
1463+ "please check your internet connection.") % \
1464+ (LAUNCHPAD_PPA_API % (user, ppa)))
1465+
1466+
1467+class PPAShortcutHandler(object):
1468+ def __init__(self, shortcut):
1469+ super(PPAShortcutHandler, self).__init__()
1470+ try:
1471+ self.shortcut = mangle_ppa_shortcut(shortcut)
1472+ except:
1473+ raise ShortcutException(_("ERROR: '{shortcut}' is not a valid ppa format")
1474+ .format(shortcut=shortcut))
1475+ info = get_ppa_info(self.shortcut)
1476+
1477+ if "private" in info and info["private"]:
1478+ raise ShortcutException(
1479+ _("Adding private PPAs is not supported currently"))
1480+
1481+ self._info = info
1482+
1483+ def info(self):
1484+ return self._info
1485+
1486+ def expand(self, codename, distro=None):
1487+ if (distro is not None
1488+ and distro != self._info["distribution"]
1489+ and not series_valid_for_distro(self._info["distribution"], codename)):
1490+ # The requested PPA is for a foreign distribution. Guess that
1491+ # the user wants that distribution's current series.
1492+ # This only applies if the local distribution is not the same
1493+ # distribution the remote PPA is associated with AND the local
1494+ # codename is not equal to the PPA's series.
1495+ # e.g. local:Foobar/xenial and ppa:Ubuntu/xenial will use 'xenial'
1496+ # local:Foobar/fluffy and ppa:Ubuntu/xenial will use '$latest'
1497+ codename = get_current_series_from_lp(self._info["distribution"])
1498+ debline = "deb http://ppa.launchpad.net/%s/%s/%s %s main" % (
1499+ self._info["owner"][1:], self._info["name"],
1500+ self._info["distribution"], codename)
1501+ sourceslistd = apt_pkg.config.find_dir("Dir::Etc::sourceparts")
1502+ filename = os.path.join(sourceslistd, "%s-%s-%s-%s.list" % (
1503+ encode(self._info["owner"][1:]), encode(self._info["distribution"]),
1504+ encode(self._info["name"]), codename))
1505+ return (debline, filename)
1506+
1507+ def should_confirm(self):
1508+ return True
1509+>>>>>>> softwareproperties/ppa.py
1510
1511 self._username = handler.username
1512 self._password = handler.password
1513@@ -230,9 +568,16 @@ class PPAShortcutHandler(ShortcutHandler):
1514 self._set_source_entry(handler.SourceEntry().line)
1515 return True
1516
1517+<<<<<<< softwareproperties/ppa.py
1518 def _set_auth(self):
1519 if self._lp_anon or not self.lpppa.private:
1520 return
1521+=======
1522+def shortcut_handler(shortcut):
1523+ if not shortcut.startswith("ppa:"):
1524+ return None
1525+ return PPAShortcutHandler(shortcut)
1526+>>>>>>> softwareproperties/ppa.py
1527
1528 if self._username and self._password:
1529 return
1530diff --git a/softwareproperties/shortcuts.py b/softwareproperties/shortcuts.py
1531index a6bc034..f0f81cc 100644
1532--- a/softwareproperties/shortcuts.py
1533+++ b/softwareproperties/shortcuts.py
1534@@ -33,6 +33,11 @@ SHORTCUT_HANDLERS = [
1535 URIShortcutHandler,
1536 ]
1537
1538+<<<<<<< softwareproperties/shortcuts.py
1539+=======
1540+ def add_key(self, keyserver=None):
1541+ return True
1542+>>>>>>> softwareproperties/shortcuts.py
1543
1544 def shortcut_handler(shortcut, **kwargs):
1545 for handler in SHORTCUT_HANDLERS:
1546diff --git a/tests/test_shortcuts.py b/tests/test_shortcuts.py
1547index f518d69..80f81bb 100644
1548--- a/tests/test_shortcuts.py
1549+++ b/tests/test_shortcuts.py
1550@@ -5,6 +5,7 @@ import apt
1551 from functools import partial
1552 import unittest
1553 import sys
1554+<<<<<<< tests/test_shortcuts.py
1555 import os
1556
1557 from aptsources.distro import get_distro
1558@@ -115,7 +116,31 @@ def mock_login_with(*args, **kwargs):
1559
1560 lp.people = mock_people
1561 return lp
1562+=======
1563+try:
1564+ from urllib.request import urlopen
1565+ from urllib.error import HTTPError, URLError
1566+except ImportError:
1567+ from urllib2 import HTTPError, URLError, urlopen
1568+try:
1569+ from http.client import HTTPException
1570+except ImportError:
1571+ from httplib import HTTPException
1572
1573+sys.path.insert(0, "..")
1574+
1575+from softwareproperties.SoftwareProperties import shortcut_handler
1576+from softwareproperties.shortcuts import ShortcutException
1577+from mock import patch
1578+>>>>>>> tests/test_shortcuts.py
1579+
1580+def has_network():
1581+ try:
1582+ network = urlopen("https://launchpad.net/")
1583+ network
1584+ except (URLError, HTTPException):
1585+ return False
1586+ return True
1587
1588 class ShortcutsTestcase(unittest.TestCase):
1589 enable_source = False
1590@@ -138,6 +163,7 @@ class ShortcutsTestcase(unittest.TestCase):
1591 def create_handler(self, line, handler, *args, **kwargs):
1592 return handler(line, *args, enable_source=self.enable_source, **kwargs)
1593
1594+<<<<<<< tests/test_shortcuts.py
1595 def create_handlers(self, line, handler, *args, **kwargs):
1596 handlers = handler if isinstance(handler, list) else [handler]
1597 # note, always appends shortcut_handler
1598@@ -205,6 +231,8 @@ class ShortcutsTestcase(unittest.TestCase):
1599 for shortcut in self.create_handlers(uri, URIShortcutHandler):
1600 self.check_shortcut(shortcut, line, sourcefile=URI_SOURCEFILE)
1601
1602+=======
1603+>>>>>>> tests/test_shortcuts.py
1604 @unittest.skipUnless(has_network(), "requires network")
1605 def test_shortcut_ppa(self):
1606 for ppa in VALID_PPAS:
1607@@ -249,7 +277,9 @@ class ShortcutsTestcase(unittest.TestCase):
1608 else:
1609 os.environ.pop(key, None)
1610
1611+ @unittest.skipUnless(has_network(), "requires network")
1612 def test_shortcut_cloudarchive(self):
1613+<<<<<<< tests/test_shortcuts.py
1614 for uca in VALID_UCAS:
1615 line = UCA_LINE_PROPOSED if 'proposed' in uca else UCA_LINE
1616 with self.ca_allow_codename(CODENAME):
1617@@ -276,6 +306,22 @@ class ShortcutsTestcase(unittest.TestCase):
1618
1619 class EnableSourceShortcutsTestcase(ShortcutsTestcase):
1620 enable_source = True
1621+=======
1622+ line = "cloud-archive:folsom"
1623+ handler = shortcut_handler(line)
1624+ self.assertEqual(
1625+ ('deb http://ubuntu-cloud.archive.canonical.com/ubuntu '\
1626+ 'precise-updates/folsom main',
1627+ '/etc/apt/sources.list.d/cloudarchive-folsom.list'),
1628+ handler.expand("precise", distro="ubuntu"))
1629+
1630+ def test_shortcut_exception(self):
1631+ with self.assertRaises(ShortcutException):
1632+ with patch('softwareproperties.ppa.get_ppa_info_from_lp',
1633+ side_effect=lambda *args: HTTPError("url", 404, "not found", [], None)):
1634+ shortcut_handler("ppa:mvo")
1635+
1636+>>>>>>> tests/test_shortcuts.py
1637
1638
1639 if __name__ == "__main__":

Subscribers

People subscribed via source and target branches