1
0
mirror of https://github.com/esp8266/Arduino.git synced 2025-06-16 11:21:18 +03:00

Merge branch 'master' into esp8266

* master: (414 commits)
  Don't export sketch if the underlying core does not support it. Fixes #3171
  RSyntaxTextArea: using a modified version, tracked at https://github.com/arduino/RSyntaxTextArea. Fixes #3099
  Updated keywords.txt
  New editor on MacOSX: since CMD+J is known as "jump to selection" and the editor has no such feature, CMD+J is disabled on mac. See #3098
  Old Preferences class remains for backwards compatibility as a delegate for PreferencesData
  New Preferences window: renders fine on every OS and it's easier to adapt using NetBeans as visual editor. Fixes #3140
  Remove spawn from exec command
  Removed redundant call to File.deleteIfExists()
  Removed buggy redundant check in FileUtils.deleteIfExists()
  Restored current line/current selected lines display on lower left of the IDE. Fixes #3134
  Updated cursor.ino
  New editor on MacOSX: restored CMD+E for finding selected text
  New editor on MacOSX: CMD+UP/DOWN moves cursor to start or end of sketch. See #3098
  New editor on MacOSX: CMD+BACKSPACE deletes current line until cursor position, ALT+BACKSPACE deletes previous word. See #3098
  ArduinoIDE is in the default package. Removed
  Fixes  #2969:
  Fix Uncategorized warning message
  New editor: ALT+ BACKSPACE deletes next word (OSX only). See #3098
  New editor: ALT+ UP/DOWN move current line only if "editor.advanced" (hidden pref) is true. Fixes #3101
  New editor: mark occurrences enable when "editor.advanced" (hidden pref) is true. Fixes #3102
  ...

Conflicts:
	.gitignore
	build/build.xml
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/keywords.txt
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/library.properties
	hardware/esp8266com/esp8266/libraries/ESP8266WiFi/src/ESP8266WiFi.h
	libraries/WiFi/README.adoc
	libraries/WiFi/src/WiFi.cpp
	libraries/WiFi/src/WiFiClient.cpp
	libraries/WiFi/src/WiFiClient.h
	libraries/WiFi/src/WiFiServer.cpp
	libraries/WiFi/src/WiFiUdp.cpp
This commit is contained in:
Ivan Grokhotkov
2015-05-18 14:54:06 +03:00
644 changed files with 37518 additions and 12166 deletions

View File

@ -9,5 +9,26 @@
<classpathentry kind="lib" path="lib/jssc-2.8.0.jar"/>
<classpathentry kind="lib" path="lib/jsch-0.1.50.jar"/>
<classpathentry kind="lib" path="lib/commons-exec-1.1.jar"/>
<classpathentry kind="lib" path="../app/lib/commons-codec-1.7.jar"/>
<classpathentry kind="lib" path="../app/lib/commons-compress-1.8.jar"/>
<classpathentry kind="lib" path="../app/lib/commons-exec-1.1.jar"/>
<classpathentry kind="lib" path="../app/lib/commons-httpclient-3.1.jar"/>
<classpathentry kind="lib" path="../app/lib/jackson-annotations-2.2.3.jar"/>
<classpathentry kind="lib" path="../app/lib/jackson-core-2.2.3.jar"/>
<classpathentry kind="lib" path="../app/lib/jackson-databind-2.2.3.jar"/>
<classpathentry kind="lib" path="../app/lib/jackson-module-mrbean-2.2.3.jar"/>
<classpathentry kind="lib" path="../app/lib/bcpg-jdk15on-152.jar"/>
<classpathentry kind="lib" path="../app/lib/bcprov-jdk15on-152.jar"/>
<classpathentry kind="lib" path="lib/bcpg-jdk15on-152.jar"/>
<classpathentry kind="lib" path="lib/bcprov-jdk15on-152.jar"/>
<classpathentry kind="lib" path="lib/commons-codec-1.7.jar"/>
<classpathentry kind="lib" path="lib/commons-compress-1.8.jar"/>
<classpathentry kind="lib" path="lib/commons-lang3-3.3.2.jar"/>
<classpathentry kind="lib" path="lib/guava-18.0.jar"/>
<classpathentry kind="lib" path="lib/jackson-annotations-2.2.3.jar"/>
<classpathentry kind="lib" path="lib/jackson-core-2.2.3.jar"/>
<classpathentry kind="lib" path="lib/jackson-databind-2.2.3.jar"/>
<classpathentry kind="lib" path="lib/jackson-module-mrbean-2.2.3.jar"/>
<classpathentry kind="lib" path="lib/java-semver-0.8.0.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@ -0,0 +1,16 @@
# EditorConfig is awesome: http://EditorConfig.org
# top-most EditorConfig file
root = true
# Unix-style newlines with a newline ending every file
[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 2
charset = utf-8
[*.{md,adoc}]
indent_style = space
trim_trailing_whitespace = false

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,203 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,40 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino;
public class DefaultUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread t, Throwable e) {
System.err.println(t);
e.printStackTrace();
}
}

View File

@ -0,0 +1,45 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions;
import cc.arduino.contributions.packages.DownloadableContribution;
import java.util.Comparator;
public class DownloadableContributionBuiltInAtTheBottomComparator implements Comparator<DownloadableContribution> {
@Override
public int compare(DownloadableContribution p1, DownloadableContribution p2) {
if (p1.isReadOnly() == p2.isReadOnly()) {
return 0;
}
return p1.isReadOnly() ? 1 : -1;
}
}

View File

@ -0,0 +1,50 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions;
import cc.arduino.contributions.packages.DownloadableContribution;
import java.util.Comparator;
public class DownloadableContributionVersionComparator implements Comparator<DownloadableContribution> {
private final VersionComparator versionComparator;
public DownloadableContributionVersionComparator() {
versionComparator = new VersionComparator();
}
@Override
public int compare(DownloadableContribution lib1, DownloadableContribution lib2) {
return versionComparator.compare(lib1.getParsedVersion(), lib2.getParsedVersion());
}
}

View File

@ -0,0 +1,121 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.contributions;
import org.apache.commons.compress.utils.IOUtils;
import org.bouncycastle.openpgp.*;
import org.bouncycastle.openpgp.operator.bc.BcKeyFingerprintCalculator;
import org.bouncycastle.openpgp.operator.bc.BcPGPContentVerifierBuilderProvider;
import java.io.*;
import java.util.Iterator;
public class GPGDetachedSignatureVerifier {
private String keyId;
public GPGDetachedSignatureVerifier() {
this("7F294291");
}
public GPGDetachedSignatureVerifier(String keyId) {
this.keyId = keyId;
}
public boolean verify(File signedFile, File signature, File publicKey) throws IOException, PGPException {
PGPPublicKey pgpPublicKey = readPublicKey(publicKey, keyId);
FileInputStream signatureInputStream = null;
FileInputStream signedFileInputStream = null;
try {
signatureInputStream = new FileInputStream(signature);
PGPObjectFactory pgpObjectFactory = new PGPObjectFactory(signatureInputStream, new BcKeyFingerprintCalculator());
Object nextObject;
try {
nextObject = pgpObjectFactory.nextObject();
if (!(nextObject instanceof PGPSignatureList)) {
return false;
}
} catch (IOException e) {
return false;
}
PGPSignatureList pgpSignatureList = (PGPSignatureList) nextObject;
assert pgpSignatureList.size() == 1;
PGPSignature pgpSignature = pgpSignatureList.get(0);
pgpSignature.init(new BcPGPContentVerifierBuilderProvider(), pgpPublicKey);
signedFileInputStream = new FileInputStream(signedFile);
pgpSignature.update(IOUtils.toByteArray(signedFileInputStream));
return pgpSignature.verify();
} finally {
if (signatureInputStream != null) {
signatureInputStream.close();
}
if (signedFileInputStream != null) {
signedFileInputStream.close();
}
}
}
private PGPPublicKey readPublicKey(File file, String keyId) throws IOException, PGPException {
InputStream keyIn = null;
try {
keyIn = new BufferedInputStream(new FileInputStream(file));
return readPublicKey(keyIn, keyId);
} finally {
if (keyIn != null) {
keyIn.close();
}
}
}
private PGPPublicKey readPublicKey(InputStream input, String keyId) throws IOException, PGPException {
PGPPublicKeyRingCollection pgpPub = new PGPPublicKeyRingCollection(PGPUtil.getDecoderStream(input), new BcKeyFingerprintCalculator());
Iterator keyRingIter = pgpPub.getKeyRings();
while (keyRingIter.hasNext()) {
PGPPublicKeyRing keyRing = (PGPPublicKeyRing) keyRingIter.next();
Iterator keyIter = keyRing.getPublicKeys();
while (keyIter.hasNext()) {
PGPPublicKey key = (PGPPublicKey) keyIter.next();
if (Long.toHexString(key.getKeyID()).toUpperCase().endsWith(keyId)) {
return key;
}
}
}
throw new IllegalArgumentException("Can't find encryption key in key ring.");
}
}

View File

@ -0,0 +1,16 @@
package cc.arduino.contributions;
import processing.app.I18n;
import static processing.app.I18n._;
public class SignatureVerificationFailedException extends Exception {
public SignatureVerificationFailedException(String filename) {
super(I18n.format(_("{0} file signature verification failed"), filename));
}
public SignatureVerificationFailedException(String filename, Throwable cause) {
super(I18n.format(_("{0} file signature verification failed"), filename), cause);
}
}

View File

@ -0,0 +1,71 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions;
import com.github.zafarkhaja.semver.Version;
import java.util.Comparator;
public class VersionComparator implements Comparator<String> {
@Override
public int compare(String a, String b) {
// null is always less than any other value
if (a == null && b == null)
return 0;
if (a == null)
return -1;
if (b == null)
return 1;
Version versionA = VersionHelper.valueOf(a);
Version versionB = VersionHelper.valueOf(b);
return versionA.compareTo(versionB);
}
public boolean greaterThan(String a, String b) {
// null is always less than any other value
if (a == null && b == null) {
return false;
}
if (a == null) {
return false;
}
if (b == null) {
return true;
}
Version versionA = VersionHelper.valueOf(a);
Version versionB = VersionHelper.valueOf(b);
return versionA.greaterThan(versionB);
}
}

View File

@ -0,0 +1,57 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions;
import com.github.zafarkhaja.semver.Version;
public class VersionHelper {
public static Version valueOf(String ver) {
if (ver == null) {
return null;
}
try {
String[] verParts = ver.split("\\.");
if (verParts.length < 3) {
if (verParts.length == 2) {
return Version.forIntegers(Integer.valueOf(verParts[0]), Integer.valueOf(verParts[1]));
} else {
return Version.forIntegers(Integer.valueOf(verParts[0]));
}
} else {
return Version.valueOf(ver);
}
} catch (Exception e) {
System.err.println("Invalid version found: " + ver);
return null;
}
}
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.filters;
import cc.arduino.contributions.packages.DownloadableContribution;
import com.google.common.base.Predicate;
public class BuiltInPredicate implements Predicate<DownloadableContribution> {
@Override
public boolean apply(DownloadableContribution input) {
return input.isReadOnly();
}
@Override
public boolean equals(Object obj) {
return obj instanceof BuiltInPredicate;
}
}

View File

@ -0,0 +1,47 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.filters;
import cc.arduino.contributions.packages.DownloadableContribution;
import com.google.common.base.Predicate;
public class DownloadableContributionWithVersionPredicate implements Predicate<DownloadableContribution> {
private final String version;
public DownloadableContributionWithVersionPredicate(String version) {
this.version = version;
}
@Override
public boolean apply(DownloadableContribution contribution) {
return version.equals(contribution.getParsedVersion());
}
}

View File

@ -0,0 +1,46 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.filters;
import cc.arduino.contributions.packages.DownloadableContribution;
import com.google.common.base.Predicate;
public class InstalledPredicate implements Predicate<DownloadableContribution> {
@Override
public boolean apply(DownloadableContribution input) {
return input.isInstalled();
}
@Override
public boolean equals(Object obj) {
return obj instanceof DownloadableContribution;
}
}

View File

@ -0,0 +1,153 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries;
import cc.arduino.contributions.packages.DownloadableContribution;
import processing.app.I18n;
import java.util.Comparator;
import java.util.List;
import static processing.app.I18n._;
public abstract class ContributedLibrary extends DownloadableContribution {
public abstract String getName();
public abstract String getMaintainer();
public abstract String getAuthor();
public abstract String getWebsite();
public abstract String getCategory();
public abstract void setCategory(String category);
public abstract String getLicense();
public abstract String getParagraph();
public abstract String getSentence();
public abstract List<String> getArchitectures();
public abstract List<String> getTypes();
public abstract List<ContributedLibraryReference> getRequires();
public static final Comparator<ContributedLibrary> CASE_INSENSITIVE_ORDER = new Comparator<ContributedLibrary>() {
@Override
public int compare(ContributedLibrary o1, ContributedLibrary o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
};
/**
* Returns <b>true</b> if the library declares to support the specified
* architecture (through the "architectures" property field).
*
* @param reqArch
* @return
*/
public boolean supportsArchitecture(String reqArch) {
return getArchitectures().contains(reqArch) || getArchitectures().contains("*");
}
/**
* Returns <b>true</b> if the library declares to support at least one of the
* specified architectures.
*
* @param reqArchs A List of architectures to check
* @return
*/
public boolean supportsArchitecture(List<String> reqArchs) {
if (reqArchs.contains("*"))
return true;
for (String reqArch : reqArchs)
if (supportsArchitecture(reqArch))
return true;
return false;
}
@Override
public String toString() {
return I18n.format(_("Version {0}"), getParsedVersion());
}
public String info() {
String res = "";
res += " ContributedLibrary : " + getName() + "\n";
res += " author : " + getAuthor() + "\n";
res += " maintainer : " + getMaintainer() + "\n";
res += " version : " + getParsedVersion() + "\n";
res += " website : " + getUrl() + "\n";
res += " category : " + getCategory() + "\n";
res += " license : " + getLicense() + "\n";
res += " descrip : " + getSentence() + "\n";
if (getParagraph() != null && !getParagraph().isEmpty())
res += " " + getParagraph() + "\n";
res += " architectures : ";
if (getArchitectures() != null)
for (String a : getArchitectures()) {
res += a + ",";
}
res += "\n";
res += " requires :\n";
if (getRequires() != null)
for (ContributedLibraryReference r : getRequires()) {
res += " " + r;
}
res += "\n";
// DownloadableContribution
res += super.toString();
return res;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ContributedLibrary)) {
return false;
}
String thisVersion = getParsedVersion();
String otherVersion = ((ContributedLibrary) obj).getParsedVersion();
boolean versionEquals = thisVersion == otherVersion || (thisVersion != null && otherVersion != null && thisVersion.equals(otherVersion));
String thisName = getName();
String otherName = ((ContributedLibrary) obj).getName();
boolean nameEquals = thisName == null || otherName == null || thisName.equals(otherName);
return versionEquals && nameEquals;
}
}

View File

@ -0,0 +1,43 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries;
public abstract class ContributedLibraryReference {
public abstract String getName();
public abstract String getMaintainer();
public abstract String getVersion();
@Override
public String toString() {
return getName() + " " + getVersion() + " (" + getMaintainer() + ")";
}
}

View File

@ -0,0 +1,104 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries;
import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.libraries.filters.LibraryWithNamePredicate;
import com.google.common.collect.Collections2;
import java.util.*;
public abstract class LibrariesIndex {
public abstract List<ContributedLibrary> getLibraries();
public List<ContributedLibrary> find(final String name) {
return new LinkedList<ContributedLibrary>(Collections2.filter(getLibraries(), new LibraryWithNamePredicate(name)));
}
public ContributedLibrary find(String name, String version) {
if (name == null || version == null) {
return null;
}
for (ContributedLibrary lib : find(name)) {
if (version.equals(lib.getParsedVersion())) {
return lib;
}
}
return null;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for (ContributedLibrary library : getLibraries()) {
sb.append(library.toString());
}
return sb.toString();
}
public List<String> getCategories() {
List<String> categories = new LinkedList<String>();
for (ContributedLibrary lib : getLibraries()) {
if (lib.getCategory() != null && !categories.contains(lib.getCategory())) {
categories.add(lib.getCategory());
}
}
Collections.sort(categories);
return categories;
}
public List<String> getTypes() {
Collection<String> typesAccumulator = new HashSet<String>();
for (ContributedLibrary lib : getLibraries()) {
if (lib.getTypes() != null) {
typesAccumulator.addAll(lib.getTypes());
}
}
List<String> types = new LinkedList<String>(typesAccumulator);
Collections.sort(types);
return types;
}
public ContributedLibrary getInstalled(String name) {
List<ContributedLibrary> installedReleases = new LinkedList<ContributedLibrary>(Collections2.filter(find(name), new InstalledPredicate()));
Collections.sort(installedReleases, new DownloadableContributionBuiltInAtTheBottomComparator());
if (installedReleases.isEmpty()) {
return null;
}
return installedReleases.get(0);
}
}

View File

@ -0,0 +1,223 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.mrbean.MrBeanModule;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.helpers.FileUtils;
import processing.app.helpers.filefilters.OnlyDirs;
import processing.app.packages.LegacyUserLibrary;
import processing.app.packages.LibraryList;
import processing.app.packages.UserLibrary;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import static processing.app.I18n._;
public class LibrariesIndexer {
private LibrariesIndex index;
private final LibraryList installedLibraries = new LibraryList();
private final LibraryList installedLibrariesWithDuplicates = new LibraryList();
private List<File> librariesFolders;
private final File indexFile;
private final File stagingFolder;
private File sketchbookLibrariesFolder;
public LibrariesIndexer(File preferencesFolder) {
indexFile = new File(preferencesFolder, "library_index.json");
stagingFolder = new File(preferencesFolder, "staging" + File.separator +
"libraries");
}
public void parseIndex() throws IOException {
parseIndex(indexFile);
// TODO: resolve libraries inner references
}
private void parseIndex(File indexFile) throws IOException {
InputStream indexIn = null;
try {
indexIn = new FileInputStream(indexFile);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new MrBeanModule());
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
index = mapper.readValue(indexIn, LibrariesIndex.class);
for (ContributedLibrary library : index.getLibraries()) {
if (library.getCategory() == null || "".equals(library.getCategory())) {
library.setCategory("Uncategorized");
}
}
} finally {
if (indexIn != null) {
indexIn.close();
}
}
}
public void setLibrariesFolders(List<File> _librariesFolders) {
librariesFolders = _librariesFolders;
rescanLibraries();
}
public void rescanLibraries() {
// Clear all installed flags
installedLibraries.clear();
installedLibrariesWithDuplicates.clear();
for (ContributedLibrary lib : index.getLibraries())
lib.setInstalled(false);
// Rescan libraries
for (File folder : librariesFolders)
scanInstalledLibraries(folder, folder.equals(sketchbookLibrariesFolder));
}
private void scanInstalledLibraries(File folder, boolean isSketchbook) {
File list[] = folder.listFiles(OnlyDirs.ONLY_DIRS);
// if a bad folder or something like that, this might come back null
if (list == null)
return;
for (File subfolder : list) {
if (!BaseNoGui.isSanitaryName(subfolder.getName())) {
String mess = I18n.format(_("The library \"{0}\" cannot be used.\n"
+ "Library names must contain only basic letters and numbers.\n"
+ "(ASCII only and no spaces, and it cannot start with a number)"),
subfolder.getName());
BaseNoGui.showMessage(_("Ignoring bad library name"), mess);
continue;
}
try {
scanLibrary(subfolder, isSketchbook);
} catch (IOException e) {
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"), subfolder, e.getMessage()));
}
}
}
private void scanLibrary(File folder, boolean isSketchbook) throws IOException {
boolean readOnly = !FileUtils.isSubDirectory(sketchbookLibrariesFolder, folder);
// A library is considered "legacy" if it doesn't contains
// a file called "library.properties"
File check = new File(folder, "library.properties");
if (!check.exists() || !check.isFile()) {
// Create a legacy library and exit
LegacyUserLibrary lib = LegacyUserLibrary.create(folder);
lib.setReadOnly(readOnly);
installedLibraries.addOrReplace(lib);
if (isSketchbook) {
installedLibrariesWithDuplicates.add(lib);
} else {
installedLibrariesWithDuplicates.addOrReplace(lib);
}
return;
}
// Create a regular library
UserLibrary lib = UserLibrary.create(folder);
lib.setReadOnly(readOnly);
installedLibraries.addOrReplace(lib);
if (isSketchbook) {
installedLibrariesWithDuplicates.add(lib);
} else {
installedLibrariesWithDuplicates.addOrReplace(lib);
}
// Check if we can find the same library in the index
// and mark it as installed
ContributedLibrary foundLib = index.find(lib.getName(), lib.getParsedVersion());
if (foundLib != null) {
foundLib.setInstalled(true);
foundLib.setInstalledFolder(folder);
foundLib.setReadOnly(readOnly);
lib.setTypes(foundLib.getTypes());
}
if (lib.isReadOnly() && lib.getTypes() == null && !lib.getDeclaredTypes().isEmpty()) {
lib.setTypes(lib.getDeclaredTypes());
}
if (lib.getTypes() == null) {
lib.setTypes(Arrays.asList("Contributed"));
}
}
public LibrariesIndex getIndex() {
return index;
}
public LibraryList getInstalledLibraries() {
return installedLibraries;
}
// Same as getInstalledLibraries(), but allow duplicates between
// builtin+package libraries and sketchbook installed libraries.
// However, do not report duplicates among builtin and packages, to
// allow any package to override builtin libraries without being
// reported as duplicates.
public LibraryList getInstalledLibrariesWithDuplicates() {
return installedLibrariesWithDuplicates;
}
public File getStagingFolder() {
return stagingFolder;
}
/**
* Set the sketchbook library folder. <br />
* New libraries will be installed here. <br />
* Libraries not found on this folder will be marked as read-only.
*
* @param folder
*/
public void setSketchbookLibrariesFolder(File folder) {
this.sketchbookLibrariesFolder = folder;
}
public File getSketchbookLibrariesFolder() {
return sketchbookLibrariesFolder;
}
public File getIndexFile() {
return indexFile;
}
}

View File

@ -0,0 +1,172 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries;
import cc.arduino.contributions.packages.DownloadableContributionsDownloader;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
import cc.arduino.utils.Progress;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.helpers.FileUtils;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import static processing.app.I18n._;
public class LibraryInstaller {
private static final String LIBRARY_INDEX_URL;
static {
String externalLibraryIndexUrl = System.getProperty("LIBRARY_INDEX_URL");
if (externalLibraryIndexUrl != null && !"".equals(externalLibraryIndexUrl)) {
LIBRARY_INDEX_URL = externalLibraryIndexUrl;
} else {
LIBRARY_INDEX_URL = "http://downloads.arduino.cc/libraries/library_index.json";
}
}
private final LibrariesIndexer indexer;
private final DownloadableContributionsDownloader downloader;
public LibraryInstaller(LibrariesIndexer _indexer) {
indexer = _indexer;
File stagingFolder = _indexer.getStagingFolder();
downloader = new DownloadableContributionsDownloader(stagingFolder) {
@Override
protected void onProgress(Progress progress) {
LibraryInstaller.this.onProgress(progress);
}
};
}
public void updateIndex() throws Exception {
final MultiStepProgress progress = new MultiStepProgress(2);
// Step 1: Download index
URL url = new URL(LIBRARY_INDEX_URL);
File outputFile = indexer.getIndexFile();
File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp");
try {
downloader.download(url, tmpFile, progress,
_("Downloading libraries index..."));
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
}
progress.stepDone();
// TODO: Check downloaded index
// Replace old index with the updated one
if (outputFile.exists())
outputFile.delete();
if (!tmpFile.renameTo(outputFile))
throw new Exception(
_("An error occurred while updating libraries index!"));
// Step 2: Rescan index
rescanLibraryIndex(progress);
}
public void install(ContributedLibrary lib, ContributedLibrary replacedLib) throws Exception {
if (lib.isInstalled()) {
System.out.println(I18n.format(_("Library is already installed: {0} version {1}"), lib.getName(), lib.getParsedVersion()));
return;
}
final MultiStepProgress progress = new MultiStepProgress(3);
// Step 1: Download library
try {
downloader.download(lib, progress, I18n.format(_("Downloading library: {0}"), lib.getName()));
} catch (InterruptedException e) {
// Download interrupted... just exit
return;
}
// TODO: Extract to temporary folders and move to the final destination only
// once everything is successfully unpacked. If the operation fails remove
// all the temporary folders and abort installation.
// Step 2: Unpack library on the correct location
progress.setStatus(I18n.format(_("Installing library: {0}"), lib.getName()));
onProgress(progress);
File libsFolder = indexer.getSketchbookLibrariesFolder();
File tmpFolder = FileUtils.createTempFolderIn(libsFolder);
try {
new ArchiveExtractor(BaseNoGui.getPlatform()).extract(lib.getDownloadedFile(), tmpFolder, 1);
} catch (Exception e) {
if (tmpFolder.exists())
FileUtils.recursiveDelete(tmpFolder);
}
progress.stepDone();
// Step 3: Remove replaced library and move installed one to the correct location
// TODO: Fix progress bar...
remove(replacedLib);
File destFolder = new File(libsFolder, lib.getName().replaceAll(" ", "_"));
tmpFolder.renameTo(destFolder);
progress.stepDone();
// Step 4: Rescan index
rescanLibraryIndex(progress);
}
public void remove(ContributedLibrary lib) throws IOException {
if (lib == null || lib.isReadOnly()) {
return;
}
final MultiStepProgress progress = new MultiStepProgress(2);
// Step 1: Remove library
progress.setStatus(I18n.format(_("Removing library: {0}"), lib.getName()));
onProgress(progress);
FileUtils.recursiveDelete(lib.getInstalledFolder());
progress.stepDone();
// Step 2: Rescan index
rescanLibraryIndex(progress);
}
private void rescanLibraryIndex(MultiStepProgress progress) {
progress.setStatus(_("Updating list of installed libraries"));
onProgress(progress);
indexer.rescanLibraries();
progress.stepDone();
}
protected void onProgress(Progress progress) {
// Empty
}
}

View File

@ -0,0 +1,48 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.libraries.filters;
import cc.arduino.contributions.libraries.ContributedLibrary;
import com.google.common.base.Predicate;
public class LibraryWithNamePredicate implements Predicate<ContributedLibrary> {
private final String name;
public LibraryWithNamePredicate(String name) {
this.name = name;
}
@Override
public boolean apply(ContributedLibrary contributedLibrary) {
return name.equals(contributedLibrary.getName());
}
}

View File

@ -0,0 +1,23 @@
package cc.arduino.contributions.packages;
import java.util.Arrays;
import java.util.List;
public class Constants {
public static final String DEFAULT_INDEX_FILE_NAME = "package_index.json";
public static final List<String> PROTECTED_PACKAGE_NAMES = Arrays.asList("arduino", "Intel");
public static final String PACKAGE_INDEX_URL;
public static final String PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS = "boardsmanager.additional.urls";
static {
String extenalPackageIndexUrl = System.getProperty("PACKAGE_INDEX_URL");
if (extenalPackageIndexUrl != null && !"".equals(extenalPackageIndexUrl)) {
PACKAGE_INDEX_URL = extenalPackageIndexUrl;
} else {
PACKAGE_INDEX_URL = "http://downloads.arduino.cc/packages/package_index.json";
}
}
}

View File

@ -0,0 +1,35 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
public interface ContributedBoard {
String getName();
}

View File

@ -0,0 +1,7 @@
package cc.arduino.contributions.packages;
public abstract class ContributedHelp {
public abstract String getOnline();
}

View File

@ -0,0 +1,101 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import cc.arduino.contributions.VersionComparator;
import java.util.List;
public abstract class ContributedPackage {
public abstract String getName();
public abstract String getMaintainer();
public abstract String getWebsiteURL();
public abstract String getEmail();
public abstract List<ContributedPlatform> getPlatforms();
public abstract List<ContributedTool> getTools();
public abstract ContributedHelp getHelp();
public ContributedPlatform findPlatform(String architecture, String version) {
if (architecture == null || version == null) {
return null;
}
for (ContributedPlatform platform : getPlatforms()) {
if (platform.getArchitecture().equals(architecture) && version.equals(platform.getParsedVersion()))
return platform;
}
return null;
}
public ContributedTool findTool(String name, String version) {
for (ContributedTool tool : getTools()) {
if (tool.getName().equals(name) && tool.getVersion().equals(version))
return tool;
}
return null;
}
@Override
public String toString() {
String res;
res = "Package name : " + getName() + "\n";
res += " maintaner : " + getMaintainer() + " (" + getEmail() + ")\n";
if (getPlatforms() != null) {
for (ContributedPlatform plat : getPlatforms()) {
res += "\n Plaform : name : " + plat.getName();
if (plat.isInstalled()) {
res += "\n " + plat;
}
res += "\n category : " + plat.getCategory();
res += "\n architecture : " +
plat.getArchitecture() + " " + plat.getParsedVersion() + "\n";
if (plat.getToolsDependencies() != null)
for (ContributedToolReference t : plat.getToolsDependencies()) {
res += " tool dep : " + t.getName() + " " +
t.getVersion() + "\n";
}
if (plat.getBoards() != null)
for (ContributedBoard board : plat.getBoards())
res += " board : " + board.getName() +
"\n";
}
}
if (getTools() != null) {
for (ContributedTool tool : getTools())
res += tool + "\n";
}
return res;
}
}

View File

@ -0,0 +1,96 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
public abstract class ContributedPlatform extends DownloadableContribution {
public abstract String getName();
public abstract String getCategory();
public abstract void setCategory(String category);
public abstract String getArchitecture();
public abstract String getChecksum();
public abstract List<ContributedToolReference> getToolsDependencies();
public abstract List<ContributedBoard> getBoards();
public abstract ContributedHelp getHelp();
private List<ContributedTool> resolvedTools = null;
private ContributedPackage parentPackage;
public List<ContributedTool> getResolvedTools() {
if (resolvedTools == null) {
return null;
}
return new LinkedList<ContributedTool>(resolvedTools);
}
public void resolveToolsDependencies(Collection<ContributedPackage> packages) {
resolvedTools = new ArrayList<ContributedTool>();
// If there are no dependencies return empty list
if (getToolsDependencies() == null) {
return;
}
// For each tool dependency
for (ContributedToolReference dep : getToolsDependencies()) {
// Search the referenced tool
ContributedTool tool = dep.resolve(packages);
if (tool == null) {
System.err.println("Index error: could not find referenced tool " + dep);
}
resolvedTools.add(tool);
}
}
public ContributedPackage getParentPackage() {
return parentPackage;
}
public void setParentPackage(ContributedPackage parentPackage) {
this.parentPackage = parentPackage;
}
@Override
public String toString() {
return getParsedVersion();
}
}

View File

@ -0,0 +1,85 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
public class ContributedTargetPackage implements TargetPackage {
private final String id;
private final Map<String, TargetPlatform> platforms;
public ContributedTargetPackage(String _id) {
id = _id;
platforms = new HashMap<String, TargetPlatform>();
}
void addPlatform(TargetPlatform p) {
platforms.put(p.getId(), p);
}
boolean hasPlatforms() {
return platforms.size() > 0;
}
@Override
public String getId() {
return id;
}
@Override
public Map<String, TargetPlatform> getPlatforms() {
return platforms;
}
@Override
public Collection<TargetPlatform> platforms() {
return platforms.values();
}
@Override
public TargetPlatform get(String platform) {
return platforms.get(platform);
}
@Override
public boolean hasPlatform(TargetPlatform platform) {
return platforms.containsKey(platform.getId());
}
@Override
public String toString() {
return "TargetPackage: " + getId();
}
}

View File

@ -0,0 +1,45 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import java.io.File;
import processing.app.debug.LegacyTargetPlatform;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatformException;
public class ContributedTargetPlatform extends LegacyTargetPlatform {
public ContributedTargetPlatform(String _name, File _folder,
TargetPackage parent,
ContributionsIndex index)
throws TargetPlatformException {
super(_name, _folder, parent);
}
}

View File

@ -0,0 +1,63 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import processing.app.BaseNoGui;
import java.util.List;
public abstract class ContributedTool {
public abstract String getName();
public abstract String getVersion();
public abstract List<HostDependentDownloadableContribution> getSystems();
public DownloadableContribution getDownloadableContribution() {
for (HostDependentDownloadableContribution c : getSystems()) {
if (c.isCompatible(BaseNoGui.getPlatform()))
return c;
}
return null;
}
@Override
public String toString() {
String res;
res = "Tool name : " + getName() + " " + getVersion() + "\n";
for (HostDependentDownloadableContribution sys : getSystems()) {
res += " sys";
res += sys.isCompatible(BaseNoGui.getPlatform()) ? "*" : " ";
res += " : " + sys + "\n";
}
return res;
}
}

View File

@ -0,0 +1,57 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import java.util.Collection;
public abstract class ContributedToolReference {
public abstract String getName();
public abstract String getVersion();
public abstract String getPackager();
public ContributedTool resolve(Collection<ContributedPackage> packages) {
for (ContributedPackage pack : packages) {
for (ContributedTool tool : pack.getTools())
if (tool.getName().equals(getName()) &&
tool.getVersion().equals(getVersion()) &&
pack.getName().equals(getPackager()))
return tool;
}
return null;
}
@Override
public String toString() {
return "name=" + getName() + " version=" + getVersion() + " packager=" +
getPackager();
}
}

View File

@ -0,0 +1,302 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
import cc.arduino.filters.FileExecutablePredicate;
import cc.arduino.utils.ArchiveExtractor;
import cc.arduino.utils.MultiStepProgress;
import cc.arduino.utils.Progress;
import com.google.common.collect.Collections2;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.Executor;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.PreferencesData;
import processing.app.helpers.FileUtils;
import processing.app.helpers.filefilters.OnlyDirs;
import processing.app.tools.CollectStdOutStdErrExecutor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import static processing.app.I18n._;
import static processing.app.I18n.format;
public class ContributionInstaller {
private final ContributionsIndexer indexer;
private final DownloadableContributionsDownloader downloader;
public ContributionInstaller(ContributionsIndexer contributionsIndexer) {
File stagingFolder = contributionsIndexer.getStagingFolder();
indexer = contributionsIndexer;
downloader = new DownloadableContributionsDownloader(stagingFolder) {
@Override
protected void onProgress(Progress progress) {
ContributionInstaller.this.onProgress(progress);
}
};
}
public List<String> install(ContributedPlatform platform) throws Exception {
List<String> errors = new LinkedList<String>();
if (platform.isInstalled()) {
throw new Exception("Platform is already installed!");
}
// Do not download already installed tools
List<ContributedTool> tools = new LinkedList<ContributedTool>(platform.getResolvedTools());
Iterator<ContributedTool> toolsIterator = tools.iterator();
while (toolsIterator.hasNext()) {
ContributedTool tool = toolsIterator.next();
DownloadableContribution downloadable = tool.getDownloadableContribution();
if (downloadable == null) {
throw new Exception(format(_("Tool {0} is not available for your operating system."), tool.getName()));
}
if (downloadable.isInstalled()) {
toolsIterator.remove();
}
}
// Calculate progress increases
MultiStepProgress progress = new MultiStepProgress((tools.size() + 1) * 2);
// Download all
try {
// Download platform
downloader.download(platform, progress, _("Downloading boards definitions."));
progress.stepDone();
// Download tools
int i = 1;
for (ContributedTool tool : tools) {
String msg = format(_("Downloading tools ({0}/{1})."), i, tools.size());
i++;
downloader.download(tool.getDownloadableContribution(), progress, msg);
progress.stepDone();
}
} catch (InterruptedException e) {
// Download interrupted... just exit
return errors;
}
ContributedPackage pack = platform.getParentPackage();
File packageFolder = new File(indexer.getPackagesFolder(), pack.getName());
// TODO: Extract to temporary folders and move to the final destination only
// once everything is successfully unpacked. If the operation fails remove
// all the temporary folders and abort installation.
// Unzip tools on the correct location
File toolsFolder = new File(packageFolder, "tools");
int i = 1;
for (ContributedTool tool : tools) {
progress.setStatus(format(_("Installing tools ({0}/{1})..."), i, tools.size()));
onProgress(progress);
i++;
DownloadableContribution toolContrib = tool.getDownloadableContribution();
File destFolder = new File(toolsFolder, tool.getName() + File.separator + tool.getVersion());
destFolder.mkdirs();
assert toolContrib.getDownloadedFile() != null;
new ArchiveExtractor(BaseNoGui.getPlatform()).extract(toolContrib.getDownloadedFile(), destFolder, 1);
try {
executePostInstallScriptIfAny(destFolder);
} catch (IOException e) {
errors.add(_("Error running post install script"));
}
toolContrib.setInstalled(true);
toolContrib.setInstalledFolder(destFolder);
progress.stepDone();
}
// Unpack platform on the correct location
progress.setStatus(_("Installing boards..."));
onProgress(progress);
File platformFolder = new File(packageFolder, "hardware" + File.separator + platform.getArchitecture());
File destFolder = new File(platformFolder, platform.getParsedVersion());
destFolder.mkdirs();
new ArchiveExtractor(BaseNoGui.getPlatform()).extract(platform.getDownloadedFile(), destFolder, 1);
platform.setInstalled(true);
platform.setInstalledFolder(destFolder);
progress.stepDone();
progress.setStatus(_("Installation completed!"));
onProgress(progress);
return errors;
}
private void executePostInstallScriptIfAny(File folder) throws IOException {
Collection<File> postInstallScripts = Collections2.filter(BaseNoGui.getPlatform().postInstallScripts(folder), new FileExecutablePredicate());
if (postInstallScripts.isEmpty()) {
String[] subfolders = folder.list(new OnlyDirs());
if (subfolders.length != 1) {
return;
}
executePostInstallScriptIfAny(new File(folder, subfolders[0]));
return;
}
File postInstallScript = postInstallScripts.iterator().next();
ByteArrayOutputStream stdout = new ByteArrayOutputStream();
ByteArrayOutputStream stderr = new ByteArrayOutputStream();
Executor executor = new CollectStdOutStdErrExecutor(stdout, stderr);
executor.setWorkingDirectory(folder);
executor.setExitValues(null);
int exitValue = executor.execute(new CommandLine(postInstallScript));
executor.setExitValues(new int[0]);
System.out.write(stdout.toByteArray());
System.err.write(stderr.toByteArray());
if (executor.isFailure(exitValue)) {
throw new IOException();
}
}
public List<String> remove(ContributedPlatform platform) {
if (platform == null || platform.isReadOnly()) {
return new LinkedList<String>();
}
List<String> errors = new LinkedList<String>();
FileUtils.recursiveDelete(platform.getInstalledFolder());
platform.setInstalled(false);
platform.setInstalledFolder(null);
// Check if the tools are no longer needed
for (ContributedTool tool : platform.getResolvedTools()) {
if (indexer.isContributedToolUsed(tool)) {
continue;
}
DownloadableContribution toolContrib = tool.getDownloadableContribution();
File destFolder = toolContrib.getInstalledFolder();
FileUtils.recursiveDelete(destFolder);
toolContrib.setInstalled(false);
toolContrib.setInstalledFolder(null);
// We removed the version folder (.../tools/TOOL_NAME/VERSION)
// now try to remove the containing TOOL_NAME folder
// (and silently fail if another version of the tool is installed)
try {
destFolder.getParentFile().delete();
} catch (SecurityException e) {
// ignore
}
}
return errors;
}
public List<String> updateIndex() throws Exception {
MultiStepProgress progress = new MultiStepProgress(1);
List<String> downloadedPackageIndexFilesAccumulator = new LinkedList<String>();
downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, Constants.PACKAGE_INDEX_URL);
Set<String> packageIndexURLs = new HashSet<String>();
String additionalURLs = PreferencesData.get(Constants.PREFERENCES_BOARDS_MANAGER_ADDITIONAL_URLS, "");
if (!"".equals(additionalURLs)) {
packageIndexURLs.addAll(Arrays.asList(additionalURLs.split(",")));
}
for (String packageIndexURL : packageIndexURLs) {
downloadIndexAndSignature(progress, downloadedPackageIndexFilesAccumulator, packageIndexURL);
}
progress.stepDone();
return downloadedPackageIndexFilesAccumulator;
}
private void downloadIndexAndSignature(MultiStepProgress progress, List<String> downloadedPackagedIndexFilesAccumulator, String packageIndexUrl) throws Exception {
File packageIndex = download(progress, packageIndexUrl);
downloadedPackagedIndexFilesAccumulator.add(packageIndex.getName());
try {
File packageIndexSignature = download(progress, packageIndexUrl + ".sig");
boolean signatureVerified = new GPGDetachedSignatureVerifier().verify(packageIndex, packageIndexSignature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key"));
if (signatureVerified) {
downloadedPackagedIndexFilesAccumulator.add(packageIndexSignature.getName());
} else {
downloadedPackagedIndexFilesAccumulator.remove(packageIndex.getName());
packageIndex.delete();
packageIndexSignature.delete();
System.err.println(I18n.format(_("{0} file signature verification failed. File ignored."), packageIndexUrl));
}
} catch (Exception e) {
//ignore errors
}
}
private File download(MultiStepProgress progress, String packageIndexUrl) throws Exception {
String statusText = _("Downloading platforms index...");
URL url = new URL(packageIndexUrl);
String[] urlPathParts = url.getFile().split("/");
File outputFile = indexer.getIndexFile(urlPathParts[urlPathParts.length - 1]);
File tmpFile = new File(outputFile.getAbsolutePath() + ".tmp");
downloader.download(url, tmpFile, progress, statusText);
// Replace old index with the updated one
if (outputFile.exists()) {
if (!outputFile.delete()) {
throw new Exception("An error occurred while updating platforms index! I can't delete file " + outputFile);
}
}
if (!tmpFile.renameTo(outputFile)) {
throw new Exception("An error occurred while updating platforms index! I can't rename file " + tmpFile);
}
return outputFile;
}
protected void onProgress(Progress progress) {
// Empty
}
public void deleteUnknownFiles(List<String> downloadedPackageIndexFiles) {
File preferencesFolder = indexer.getIndexFile(".").getParentFile();
File[] additionalPackageIndexFiles = preferencesFolder.listFiles(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME));
if (additionalPackageIndexFiles == null) {
return;
}
for (File additionalPackageIndexFile : additionalPackageIndexFiles) {
if (!downloadedPackageIndexFiles.contains(additionalPackageIndexFile.getName())) {
additionalPackageIndexFile.delete();
}
}
}
}

View File

@ -0,0 +1,151 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
import cc.arduino.contributions.filters.DownloadableContributionWithVersionPredicate;
import cc.arduino.contributions.filters.InstalledPredicate;
import cc.arduino.contributions.packages.filters.PlatformArchitecturePredicate;
import com.google.common.base.Function;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import java.util.*;
public abstract class ContributionsIndex {
public abstract List<ContributedPackage> getPackages();
public ContributedPackage findPackage(String packageName) {
for (ContributedPackage pack : getPackages()) {
if (pack.getName().equals(packageName))
return pack;
}
return null;
}
public List<ContributedPlatform> findPlatforms(String packageName, final String platformArch) {
if (packageName == null || platformArch == null) {
return null;
}
ContributedPackage aPackage = findPackage(packageName);
if (aPackage == null) {
return null;
}
Collection<ContributedPlatform> platforms = Collections2.filter(aPackage.getPlatforms(), new PlatformArchitecturePredicate(platformArch));
return Lists.newLinkedList(platforms);
}
public ContributedPlatform findPlatform(String packageName, final String platformArch, final String platformVersion) {
if (platformVersion == null) {
return null;
}
Collection<ContributedPlatform> platformsByName = findPlatforms(packageName, platformArch);
if (platformsByName == null) {
return null;
}
Collection<ContributedPlatform> platforms = Collections2.filter(platformsByName, new DownloadableContributionWithVersionPredicate(platformVersion));
if (platforms.isEmpty()) {
return null;
}
return platforms.iterator().next();
}
public ContributedPlatform getInstalled(String packageName, String platformArch) {
List<ContributedPlatform> installedPlatforms = new LinkedList<ContributedPlatform>(Collections2.filter(findPlatforms(packageName, platformArch), new InstalledPredicate()));
Collections.sort(installedPlatforms, new DownloadableContributionBuiltInAtTheBottomComparator());
if (installedPlatforms.isEmpty()) {
return null;
}
return installedPlatforms.get(0);
}
public List<ContributedPlatform> getPlatforms() {
return Lists.newLinkedList(Iterables.concat(Collections2.transform(getPackages(), new Function<ContributedPackage, List<ContributedPlatform>>() {
@Override
public List<ContributedPlatform> apply(ContributedPackage contributedPackage) {
return contributedPackage.getPlatforms();
}
})));
}
public ContributedTool findTool(String packageName, String name,
String version) {
ContributedPackage pack = findPackage(packageName);
if (pack == null)
return null;
return pack.findTool(name, version);
}
private final List<String> categories = new ArrayList<String>();
public List<String> getCategories() {
return categories;
}
public void fillCategories() {
categories.clear();
for (ContributedPackage pack : getPackages()) {
for (ContributedPlatform platform : pack.getPlatforms()) {
if (!categories.contains(platform.getCategory()))
categories.add(platform.getCategory());
}
}
}
public ContributedPackage getPackage(String packageName) {
for (ContributedPackage pack : getPackages()) {
if (pack.getName().equals(packageName)) {
return pack;
}
}
return null;
}
@Override
public String toString() {
String res = "";
res += "Categories: ";
for (String c : getCategories())
res += "'" + c + "' ";
res += "\n";
for (ContributedPackage pack : getPackages())
res += pack + "\n";
return res;
}
}

View File

@ -0,0 +1,403 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import cc.arduino.contributions.DownloadableContributionBuiltInAtTheBottomComparator;
import cc.arduino.contributions.GPGDetachedSignatureVerifier;
import cc.arduino.contributions.SignatureVerificationFailedException;
import cc.arduino.contributions.filters.BuiltInPredicate;
import cc.arduino.contributions.filters.InstalledPredicate;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.mrbean.MrBeanModule;
import com.google.common.base.Function;
import com.google.common.base.Predicates;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.Multimaps;
import processing.app.BaseNoGui;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
import processing.app.debug.TargetPlatformException;
import processing.app.helpers.PreferencesMap;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS;
public class ContributionsIndexer {
private final File packagesFolder;
private final File stagingFolder;
private final File preferencesFolder;
private ContributionsIndex index;
public ContributionsIndexer(File preferencesFolder) {
this.preferencesFolder = preferencesFolder;
packagesFolder = new File(preferencesFolder, "packages");
stagingFolder = new File(preferencesFolder, "staging" + File.separator + "packages");
}
public void parseIndex() throws Exception {
File defaultIndexFile = getIndexFile(Constants.DEFAULT_INDEX_FILE_NAME);
if (!isSigned(defaultIndexFile)) {
throw new SignatureVerificationFailedException(Constants.DEFAULT_INDEX_FILE_NAME);
}
index = parseIndex(defaultIndexFile);
File[] indexFiles = preferencesFolder.listFiles(new TestPackageIndexFilenameFilter(new PackageIndexFilenameFilter(Constants.DEFAULT_INDEX_FILE_NAME)));
for (File indexFile : indexFiles) {
ContributionsIndex contributionsIndex = parseIndex(indexFile);
mergeContributions(contributionsIndex, indexFile);
}
List<ContributedPackage> packages = index.getPackages();
for (ContributedPackage pack : packages) {
for (ContributedPlatform platform : pack.getPlatforms()) {
// Set a reference to parent packages
platform.setParentPackage(pack);
// Resolve tools dependencies (works also as a check for file integrity)
platform.resolveToolsDependencies(packages);
}
}
index.fillCategories();
}
private void mergeContributions(ContributionsIndex contributionsIndex, File indexFile) {
boolean signed = isSigned(indexFile);
for (ContributedPackage contributedPackage : contributionsIndex.getPackages()) {
if (!signed) {
for (ContributedPlatform contributedPlatform : contributedPackage.getPlatforms()) {
contributedPlatform.setCategory("Contributed");
}
}
ContributedPackage targetPackage = index.getPackage(contributedPackage.getName());
if (targetPackage == null) {
index.getPackages().add(contributedPackage);
} else {
if (signed || !isPackageNameProtected(contributedPackage)) {
List<ContributedPlatform> platforms = contributedPackage.getPlatforms();
if (platforms == null) {
platforms = new LinkedList<ContributedPlatform>();
}
for (ContributedPlatform contributedPlatform : platforms) {
ContributedPlatform platform = targetPackage.findPlatform(contributedPlatform.getArchitecture(), contributedPlatform.getVersion());
if (platform != null) {
targetPackage.getPlatforms().remove(platform);
}
targetPackage.getPlatforms().add(contributedPlatform);
}
List<ContributedTool> tools = contributedPackage.getTools();
if (tools == null) {
tools = new LinkedList<ContributedTool>();
}
for (ContributedTool contributedTool : tools) {
ContributedTool tool = targetPackage.findTool(contributedTool.getName(), contributedTool.getVersion());
if (tool != null) {
targetPackage.getTools().remove(tool);
}
targetPackage.getTools().add(contributedTool);
}
}
}
}
}
private boolean isPackageNameProtected(ContributedPackage contributedPackage) {
return Constants.PROTECTED_PACKAGE_NAMES.contains(contributedPackage.getName());
}
private boolean isSigned(File indexFile) {
File signature = new File(indexFile.getParent(), indexFile.getName() + ".sig");
if (!signature.exists()) {
return false;
}
try {
return new GPGDetachedSignatureVerifier().verify(indexFile, signature, new File(BaseNoGui.getContentFile("lib"), "public.gpg.key"));
} catch (Exception e) {
BaseNoGui.showWarning(e.getMessage(), e.getMessage(), e);
return false;
}
}
private ContributionsIndex parseIndex(File indexFile) throws IOException {
InputStream inputStream = null;
try {
inputStream = new FileInputStream(indexFile);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new MrBeanModule());
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
mapper.configure(DeserializationFeature.EAGER_DESERIALIZER_FETCH, true);
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return mapper.readValue(inputStream, ContributionsIndex.class);
} finally {
if (inputStream != null) {
inputStream.close();
}
}
}
public void syncWithFilesystem(File hardwareFolder) throws IOException {
syncBuiltInHardwareFolder(hardwareFolder);
syncLocalPackagesFolder();
}
public void syncBuiltInHardwareFolder(File hardwareFolder) throws IOException {
if (index == null) {
return;
}
for (File folder : hardwareFolder.listFiles(ONLY_DIRS)) {
ContributedPackage pack = index.findPackage(folder.getName());
if (pack != null) {
syncBuiltInPackageWithFilesystem(pack, folder);
File toolsFolder = new File(hardwareFolder, "tools");
if (toolsFolder.isDirectory()) {
for (File toolFolder : toolsFolder.listFiles(ONLY_DIRS)) {
File builtInToolsMetadata = new File(toolFolder, "builtin_tools_versions.txt");
if (builtInToolsMetadata.isFile()) {
PreferencesMap toolsMetadata = new PreferencesMap(builtInToolsMetadata).subTree(pack.getName());
for (Map.Entry<String, String> toolMetadata : toolsMetadata.entrySet()) {
syncToolWithFilesystem(pack, toolFolder, toolMetadata.getKey(), toolMetadata.getValue());
}
}
}
}
}
}
}
private void syncBuiltInPackageWithFilesystem(ContributedPackage pack, File hardwareFolder) throws IOException {
// Scan all hardware folders and mark as installed all the tools found.
for (File platformFolder : hardwareFolder.listFiles(ONLY_DIRS)) {
File platformTxt = new File(platformFolder, "platform.txt");
String version = new PreferencesMap(platformTxt).get("version");
ContributedPlatform platform = syncHardwareWithFilesystem(pack, platformFolder, platformFolder.getName(), version);
if (platform != null) {
platform.setReadOnly(true);
}
}
}
public void syncLocalPackagesFolder() {
if (!packagesFolder.isDirectory()) {
return;
}
if (index == null) {
return;
}
// Scan all hardware folders and mark as installed all the
// platforms found.
for (File folder : packagesFolder.listFiles(ONLY_DIRS)) {
ContributedPackage pack = index.findPackage(folder.getName());
if (pack != null) {
syncPackageWithFilesystem(pack, folder);
}
}
}
private void syncPackageWithFilesystem(ContributedPackage pack, File root) {
// Scan all hardware folders and mark as installed all the tools found.
File hardwareFolder = new File(root, "hardware");
if (hardwareFolder.isDirectory()) {
for (File platformFolder : hardwareFolder.listFiles(ONLY_DIRS)) {
for (File versionFolder : platformFolder.listFiles(ONLY_DIRS)) {
syncHardwareWithFilesystem(pack, versionFolder, platformFolder.getName(), versionFolder.getName());
}
}
}
// Scan all tools folders and mark as installed all the tools found.
File toolsFolder = new File(root, "tools");
if (toolsFolder.isDirectory()) {
for (File toolFolder : toolsFolder.listFiles(ONLY_DIRS)) {
for (File versionFolder : toolFolder.listFiles(ONLY_DIRS)) {
syncToolWithFilesystem(pack, versionFolder, toolFolder.getName(), versionFolder.getName());
}
}
}
}
private void syncToolWithFilesystem(ContributedPackage pack, File installationFolder, String toolName, String version) {
ContributedTool tool = pack.findTool(toolName, version);
if (tool == null) {
return;
}
DownloadableContribution contrib = tool.getDownloadableContribution();
if (contrib == null) {
System.err.println(tool + " seems to have no downloadable contributions for your operating system, but it is installed in\n" + installationFolder);
return;
}
contrib.setInstalled(true);
contrib.setInstalledFolder(installationFolder);
}
private ContributedPlatform syncHardwareWithFilesystem(ContributedPackage pack, File installationFolder, String architecture, String version) {
ContributedPlatform platform = pack.findPlatform(architecture, version);
if (platform != null) {
platform.setInstalled(true);
platform.setReadOnly(false);
platform.setInstalledFolder(installationFolder);
}
return platform;
}
@Override
public String toString() {
return index.toString();
}
public List<TargetPackage> createTargetPackages() throws TargetPlatformException {
List<TargetPackage> packages = new ArrayList<TargetPackage>();
if (index == null) {
return packages;
}
for (ContributedPackage aPackage : index.getPackages()) {
ContributedTargetPackage targetPackage = new ContributedTargetPackage(aPackage.getName());
List<ContributedPlatform> platforms = new LinkedList<ContributedPlatform>(Collections2.filter(aPackage.getPlatforms(), new InstalledPredicate()));
Collections.sort(platforms, new DownloadableContributionBuiltInAtTheBottomComparator());
for (ContributedPlatform platform : platforms) {
String arch = platform.getArchitecture();
File folder = platform.getInstalledFolder();
TargetPlatform targetPlatform = new ContributedTargetPlatform(arch, folder, targetPackage, index);
if (!targetPackage.hasPlatform(targetPlatform)) {
targetPackage.addPlatform(targetPlatform);
}
}
if (targetPackage.hasPlatforms()) {
packages.add(targetPackage);
}
}
return packages;
}
/**
* Check if a ContributedTool is currently in use by an installed platform
*
* @param tool
* @return
*/
public boolean isContributedToolUsed(ContributedTool tool) {
for (ContributedPackage pack : index.getPackages()) {
for (ContributedPlatform platform : pack.getPlatforms()) {
if (!platform.isInstalled())
continue;
for (ContributedTool requiredTool : platform.getResolvedTools()) {
if (requiredTool.equals(tool))
return true;
}
}
}
return false;
}
public Set<ContributedTool> getInstalledTools() {
Set<ContributedTool> tools = new HashSet<ContributedTool>();
if (index == null) {
return tools;
}
for (ContributedPackage pack : index.getPackages()) {
Collection<ContributedPlatform> platforms = Collections2.filter(pack.getPlatforms(), new InstalledPredicate());
ImmutableListMultimap<String, ContributedPlatform> platformsByName = Multimaps.index(platforms, new Function<ContributedPlatform, String>() {
@Override
public String apply(ContributedPlatform contributedPlatform) {
return contributedPlatform.getName();
}
});
for (Map.Entry<String, Collection<ContributedPlatform>> entry : platformsByName.asMap().entrySet()) {
Collection<ContributedPlatform> platformsWithName = entry.getValue();
if (platformsWithName.size() > 1) {
platformsWithName = Collections2.filter(platformsWithName, Predicates.not(new BuiltInPredicate()));
}
for (ContributedPlatform platform : platformsWithName) {
tools.addAll(platform.getResolvedTools());
}
}
}
return tools;
}
public ContributionsIndex getIndex() {
return index;
}
public File getPackagesFolder() {
return packagesFolder;
}
public File getStagingFolder() {
return stagingFolder;
}
public File getIndexFile(String name) {
return new File(preferencesFolder, name);
}
public List<ContributedPackage> getPackages() {
if (index == null) {
return new LinkedList<ContributedPackage>();
}
return index.getPackages();
}
public List<String> getCategories() {
if (index == null) {
return new LinkedList<String>();
}
return index.getCategories();
}
public ContributedPlatform getInstalled(String packageName, String platformArch) {
if (index == null) {
return null;
}
return index.getInstalled(packageName, platformArch);
}
}

View File

@ -0,0 +1,112 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import cc.arduino.contributions.VersionHelper;
import com.github.zafarkhaja.semver.Version;
import java.io.File;
public abstract class DownloadableContribution {
private boolean installed;
private File installedFolder;
private boolean downloaded;
private File downloadedFile;
public abstract String getUrl();
public abstract String getVersion();
public abstract String getChecksum();
public abstract long getSize();
public abstract String getArchiveFileName();
public boolean isDownloaded() {
return downloaded;
}
public void setDownloaded(boolean downloaded) {
this.downloaded = downloaded;
}
public File getDownloadedFile() {
return downloadedFile;
}
public void setDownloadedFile(File downloadedFile) {
this.downloadedFile = downloadedFile;
}
public boolean isInstalled() {
return installed;
}
public void setInstalled(boolean installed) {
this.installed = installed;
}
public File getInstalledFolder() {
return installedFolder;
}
public void setInstalledFolder(File installedFolder) {
this.installedFolder = installedFolder;
}
private boolean readOnly;
public boolean isReadOnly() {
return readOnly;
}
public void setReadOnly(boolean readOnly) {
this.readOnly = readOnly;
}
public String getParsedVersion() {
Version version = VersionHelper.valueOf(getVersion());
if (version == null) {
return null;
}
return version.toString();
}
@Override
public String toString() {
String res = "";
if (installed) {
res += "installed on " + installedFolder.getAbsolutePath() + " (" + getSize() + " bytes)";
}
return res;
}
}

View File

@ -0,0 +1,107 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import cc.arduino.utils.FileHash;
import cc.arduino.utils.Progress;
import cc.arduino.utils.network.FileDownloader;
import java.io.File;
import java.net.URL;
import java.util.Observable;
import java.util.Observer;
import static processing.app.I18n._;
import static processing.app.I18n.format;
public class DownloadableContributionsDownloader {
private final File stagingFolder;
public DownloadableContributionsDownloader(File _stagingFolder) {
stagingFolder = _stagingFolder;
}
public File download(DownloadableContribution contribution,
final Progress progress, final String statusText)
throws Exception {
URL url = new URL(contribution.getUrl());
final File outputFile = new File(stagingFolder, contribution.getArchiveFileName());
// Ensure the existence of staging folder
stagingFolder.mkdirs();
// Need to download or resume downloading?
if (!outputFile.isFile() || (outputFile.length() < contribution.getSize())) {
download(url, outputFile, progress, statusText);
}
// Test checksum
progress.setStatus(_("Verifying archive integrity..."));
onProgress(progress);
String checksum = contribution.getChecksum();
String algo = checksum.split(":")[0];
if (!FileHash.hash(outputFile, algo).equalsIgnoreCase(checksum)) {
throw new Exception(_("CRC doesn't match. File is corrupted."));
}
contribution.setDownloaded(true);
contribution.setDownloadedFile(outputFile);
return outputFile;
}
public void download(URL url, File tmpFile, final Progress progress,
final String statusText) throws Exception {
FileDownloader downloader = new FileDownloader(url, tmpFile);
downloader.addObserver(new Observer() {
@Override
public void update(Observable o, Object arg) {
FileDownloader me = (FileDownloader) o;
String msg = "";
if (me.getDownloadSize() != null) {
long downloaded = (me.getInitialSize() + me.getDownloaded()) / 1000;
long total = (me.getInitialSize() + me.getDownloadSize()) / 1000;
msg = format(_("Downloaded {0}kb of {1}kb."), downloaded, total);
}
progress.setStatus(statusText + " " + msg);
progress.setProgress(me.getProgress());
onProgress(progress);
}
});
downloader.download();
if (!downloader.isCompleted()) {
throw new Exception(format(_("Error downloading {0}"), url), downloader.getError());
}
}
protected void onProgress(Progress progress) {
// Empty
}
}

View File

@ -0,0 +1,72 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages;
import processing.app.Platform;
public abstract class HostDependentDownloadableContribution extends DownloadableContribution {
public abstract String getHost();
@Override
public String toString() {
return getHost() + " " + super.toString();
}
public boolean isCompatible(Platform platform) {
String osName = platform.getOsName();
assert osName != null;
String osArch = platform.getOsArch();
assert osArch != null;
String host = getHost();
if (osName.contains("Linux")) {
if (osArch.contains("amd64")) {
return host.matches("x86_64-.*linux-gnu");
} else {
return host.matches("i[3456]86-.*linux-gnu");
}
}
if (osName.contains("Windows")) {
return host.matches("i[3456]86-.*mingw32") || host.matches("i[3456]86-.*cygwin");
}
if (osName.contains("Mac")) {
if (osArch.contains("x86_64")) {
return host.matches("x86_64-apple-darwin.*") || host.matches("i[3456]86-apple-darwin.*");
} else {
return host.matches("i[3456]86-apple-darwin.*");
}
}
return false;
}
}

View File

@ -0,0 +1,18 @@
package cc.arduino.contributions.packages;
import java.io.File;
import java.io.FilenameFilter;
public class PackageIndexFilenameFilter implements FilenameFilter {
private final String defaultPackageIndexFileName;
public PackageIndexFilenameFilter(String defaultPackageIndexFileName) {
this.defaultPackageIndexFileName = defaultPackageIndexFileName;
}
@Override
public boolean accept(File file, String name) {
return new File(file, name).isFile() && !defaultPackageIndexFileName.equals(name) && name.startsWith("package_") && name.endsWith("_index.json");
}
}

View File

@ -0,0 +1,27 @@
package cc.arduino.contributions.packages;
import java.io.File;
import java.io.FilenameFilter;
public class TestPackageIndexFilenameFilter implements FilenameFilter {
private final FilenameFilter parent;
public TestPackageIndexFilenameFilter(FilenameFilter parent) {
this.parent = parent;
}
public TestPackageIndexFilenameFilter() {
this(null);
}
@Override
public boolean accept(File file, String name) {
boolean result = false;
if (parent != null) {
result = parent.accept(file, name);
}
result = result || (new File(file, name).isFile() && name.startsWith("test_package_") && name.endsWith("_index.json"));
return result;
}
}

View File

@ -0,0 +1,48 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.contributions.packages.filters;
import cc.arduino.contributions.packages.ContributedPlatform;
import com.google.common.base.Predicate;
public class PlatformArchitecturePredicate implements Predicate<ContributedPlatform> {
private final String platformArch;
public PlatformArchitecturePredicate(String platformArch) {
this.platformArch = platformArch;
}
@Override
public boolean apply(ContributedPlatform contributedPlatform) {
return platformArch.equals(contributedPlatform.getArchitecture());
}
}

View File

@ -0,0 +1,47 @@
package cc.arduino.files;
import processing.app.PreferencesData;
import processing.app.helpers.FileUtils;
import java.io.File;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class DeleteFilesOnShutdown implements Runnable {
public static final DeleteFilesOnShutdown INSTANCE = new DeleteFilesOnShutdown();
public static void add(File file) {
INSTANCE.addFile(file);
}
private final List<File> files;
public DeleteFilesOnShutdown() {
this.files = new LinkedList<File>();
}
public synchronized void addFile(File file) {
this.files.add(file);
}
@Override
public void run() {
boolean preserveTempFiles = PreferencesData.getBoolean("runtime.preserve.temp.files");
if (preserveTempFiles) {
return;
}
List<File> copyOfFiles;
synchronized (this) {
copyOfFiles = new LinkedList<File>(files);
}
Collections.reverse(copyOfFiles);
for (File file : copyOfFiles) {
if (file.exists() && file.canWrite()) {
FileUtils.recursiveDelete(file);
}
}
}
}

View File

@ -0,0 +1,43 @@
/*
* This file is part of Arduino.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.filters;
import com.google.common.base.Predicate;
import java.io.File;
public class FileExecutablePredicate implements Predicate<File> {
@Override
public boolean apply(File file) {
return file.isFile() && file.exists() && file.canRead() && file.canExecute();
}
}

View File

@ -29,36 +29,27 @@
package cc.arduino.packages;
import processing.app.helpers.PreferencesMap;
import java.util.List;
public interface Discovery {
/**
* Set discovery preferences
*
* @param options
*/
public void setPreferences(PreferencesMap options);
/**
* Start discovery service
*
* @throws Exception
*/
public void start() throws Exception;
void start() throws Exception;
/**
* Stop discovery service
*/
public void stop() throws Exception;
void stop() throws Exception;
/**
* Return the list of discovered ports.
*
* @return
*/
public List<BoardPort> discovery();
List<BoardPort> listDiscoveredBoards();
}

View File

@ -63,7 +63,7 @@ public class DiscoveryManager {
try {
d.stop();
} catch (Exception e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
e.printStackTrace(); //just printing as the JVM is terminating
}
}
}
@ -74,7 +74,7 @@ public class DiscoveryManager {
public List<BoardPort> discovery() {
List<BoardPort> res = new ArrayList<BoardPort>();
for (Discovery d : discoverers) {
res.addAll(d.discovery());
res.addAll(d.listDiscoveredBoards());
}
return res;
}

View File

@ -36,8 +36,9 @@ import processing.app.debug.TargetBoard;
public class UploaderFactory {
public Uploader newUploader(TargetBoard board, BoardPort port, boolean noUploadPort) {
if (noUploadPort)
return new SerialUploader(noUploadPort);
if (noUploadPort) {
return new SerialUploader(true);
}
if ("true".equals(board.getPreferences().get("upload.via_ssh")) && port != null && "network".equals(port.getProtocol())) {
return new SSHUploader(port);

View File

@ -31,9 +31,9 @@ package cc.arduino.packages.discoverers;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Discovery;
import cc.arduino.packages.discoverers.network.BoardReachabilityFilter;
import cc.arduino.packages.discoverers.network.NetworkChecker;
import processing.app.BaseNoGui;
import processing.app.helpers.NetUtils;
import processing.app.helpers.PreferencesMap;
import processing.app.zeroconf.jmdns.ArduinoDNSTaskStarter;
@ -41,70 +41,57 @@ import javax.jmdns.*;
import javax.jmdns.impl.DNSTaskStarter;
import java.io.IOException;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.packages.discoverers.network.NetworkTopologyListener {
private Timer timer;
private final List<BoardPort> ports;
private static final int MAX_TIME_AWAITING_FOR_PACKAGES = 5000;
private final List<BoardPort> boardPortsDiscoveredWithJmDNS;
private final Map<InetAddress, JmDNS> mappedJmDNSs;
private Timer networkCheckerTimer;
private Timer boardReachabilityFilterTimer;
private final List<BoardPort> reachableBoardPorts;
public NetworkDiscovery() {
DNSTaskStarter.Factory.setClassDelegate(new ArduinoDNSTaskStarter());
this.ports = new ArrayList<BoardPort>();
this.boardPortsDiscoveredWithJmDNS = new LinkedList<BoardPort>();
this.mappedJmDNSs = new Hashtable<InetAddress, JmDNS>();
this.reachableBoardPorts = new LinkedList<BoardPort>();
}
@Override
public List<BoardPort> discovery() {
List<BoardPort> boardPorts = clonePortsList();
Iterator<BoardPort> boardPortIterator = boardPorts.iterator();
while (boardPortIterator.hasNext()) {
try {
BoardPort board = boardPortIterator.next();
InetAddress inetAddress = InetAddress.getByName(board.getAddress());
int broadcastedPort = Integer.valueOf(board.getPrefs().get("port"));
List<Integer> ports = new LinkedList<Integer>();
ports.add(broadcastedPort);
//dirty code: allows non up to date yuns to be discovered. Newer yuns will broadcast port 22
if (broadcastedPort == 80) {
ports.add(0, 22);
}
boolean reachable = NetUtils.isReachable(inetAddress, ports);
if (!reachable) {
boardPortIterator.remove();
}
} catch (UnknownHostException e) {
boardPortIterator.remove();
}
}
return boardPorts;
}
private List<BoardPort> clonePortsList() {
synchronized (this) {
return new ArrayList<BoardPort>(this.ports);
public List<BoardPort> listDiscoveredBoards() {
synchronized (reachableBoardPorts) {
return new LinkedList<BoardPort>(reachableBoardPorts);
}
}
@Override
public void setPreferences(PreferencesMap options) {
public void setReachableBoardPorts(List<BoardPort> newReachableBoardPorts) {
synchronized (reachableBoardPorts) {
this.reachableBoardPorts.clear();
this.reachableBoardPorts.addAll(newReachableBoardPorts);
}
}
public List<BoardPort> getBoardPortsDiscoveredWithJmDNS() {
synchronized (boardPortsDiscoveredWithJmDNS) {
return new LinkedList<BoardPort>(boardPortsDiscoveredWithJmDNS);
}
}
@Override
public void start() throws IOException {
this.timer = new Timer(this.getClass().getName() + " timer");
new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance()).start(timer);
this.networkCheckerTimer = new Timer(NetworkChecker.class.getName());
new NetworkChecker(this, NetworkTopologyDiscovery.Factory.getInstance()).start(networkCheckerTimer);
this.boardReachabilityFilterTimer = new Timer(BoardReachabilityFilter.class.getName());
new BoardReachabilityFilter(this).start(boardReachabilityFilterTimer);
}
@Override
public void stop() throws IOException {
timer.purge();
this.networkCheckerTimer.purge();
this.boardReachabilityFilterTimer.purge();
// we don't close each JmDNS instance as it's too slow
}
@ -125,16 +112,27 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.
@Override
public void serviceRemoved(ServiceEvent serviceEvent) {
String name = serviceEvent.getName();
synchronized (this) {
for (BoardPort port : ports) {
if (port.getBoardName().equals(name))
ports.remove(port);
synchronized (boardPortsDiscoveredWithJmDNS) {
for (BoardPort port : boardPortsDiscoveredWithJmDNS) {
if (port.getBoardName().equals(name)) {
boardPortsDiscoveredWithJmDNS.remove(port);
}
}
}
}
@Override
public void serviceResolved(ServiceEvent serviceEvent) {
int sleptFor = 0;
while (BaseNoGui.packages == null && sleptFor <= MAX_TIME_AWAITING_FOR_PACKAGES) {
try {
Thread.sleep(1000);
sleptFor += 1000;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
ServiceInfo info = serviceEvent.getInfo();
for (InetAddress inetAddress : info.getInet4Addresses()) {
String address = inetAddress.getHostAddress();
@ -147,12 +145,11 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.
board = info.getPropertyString("board");
prefs.put("board", board);
prefs.put("distro_version", info.getPropertyString("distro_version"));
prefs.put("port", "" + info.getPort());
}
prefs.put("port", "" + info.getPort());
String label = name + " at " + address;
if (board != null) {
if (board != null && BaseNoGui.packages != null) {
String boardName = BaseNoGui.getPlatform().resolveDeviceByBoardID(BaseNoGui.packages, board);
if (boardName != null) {
label += " (" + boardName + ")";
@ -166,19 +163,21 @@ public class NetworkDiscovery implements Discovery, ServiceListener, cc.arduino.
port.setPrefs(prefs);
port.setLabel(label);
synchronized (this) {
synchronized (boardPortsDiscoveredWithJmDNS) {
removeDuplicateBoards(port);
ports.add(port);
boardPortsDiscoveredWithJmDNS.add(port);
}
}
}
private void removeDuplicateBoards(BoardPort newBoard) {
Iterator<BoardPort> iterator = ports.iterator();
while (iterator.hasNext()) {
BoardPort board = iterator.next();
if (newBoard.getAddress().equals(board.getAddress())) {
iterator.remove();
synchronized (boardPortsDiscoveredWithJmDNS) {
Iterator<BoardPort> iterator = boardPortsDiscoveredWithJmDNS.iterator();
while (iterator.hasNext()) {
BoardPort board = iterator.next();
if (newBoard.getAddress().equals(board.getAddress())) {
iterator.remove();
}
}
}
}

View File

@ -31,86 +31,49 @@ package cc.arduino.packages.discoverers;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Discovery;
import processing.app.BaseNoGui;
import processing.app.Platform;
import processing.app.Serial;
import processing.app.debug.TargetBoard;
import processing.app.helpers.PreferencesMap;
import cc.arduino.packages.discoverers.serial.SerialBoardsLister;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Timer;
import static processing.app.I18n._;
public class SerialDiscovery implements Discovery {
static {
//makes transifex happy
_("Uncertified");
private Timer serialBoardsListerTimer;
private final List<BoardPort> serialBoardPorts;
public SerialDiscovery() {
this.serialBoardPorts = new LinkedList<BoardPort>();
}
@Override
public List<BoardPort> discovery() {
Platform os = BaseNoGui.getPlatform();
String devicesListOutput = os.preListAllCandidateDevices();
public List<BoardPort> listDiscoveredBoards() {
return getSerialBoardPorts();
}
List<BoardPort> res = new ArrayList<BoardPort>();
List<String> ports = Serial.list();
for (String port : ports) {
Map<String, Object> boardData = os.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput);
BoardPort boardPort = new BoardPort();
boardPort.setAddress(port);
boardPort.setProtocol("serial");
String label = port;
PreferencesMap prefs = new PreferencesMap();
if (boardData != null) {
prefs.put("vid", boardData.get("vid").toString());
prefs.put("pid", boardData.get("pid").toString());
TargetBoard board = (TargetBoard) boardData.get("board");
if (board != null) {
String warningKey = "vid." + boardData.get("vid").toString() + ".warning";
String warning = board.getPreferences().get(warningKey);
prefs.put("warning", warning);
String boardName = board.getName();
if (boardName != null) {
if (warning != null) {
label += " (" + boardName + " - " + _(warning) + ")";
} else {
label += " (" + boardName + ")";
}
}
boardPort.setBoardName(boardName);
}
}
boardPort.setLabel(label);
boardPort.setPrefs(prefs);
res.add(boardPort);
public List<BoardPort> getSerialBoardPorts() {
synchronized (serialBoardPorts) {
return new LinkedList<BoardPort>(serialBoardPorts);
}
return res;
}
@Override
public void setPreferences(PreferencesMap options) {
public void setSerialBoardPorts(List<BoardPort> newSerialBoardPorts) {
synchronized (serialBoardPorts) {
serialBoardPorts.clear();
serialBoardPorts.addAll(newSerialBoardPorts);
}
}
@Override
public void start() {
this.serialBoardsListerTimer = new Timer(SerialBoardsLister.class.getName());
new SerialBoardsLister(this).start(serialBoardsListerTimer);
}
@Override
public void stop() {
this.serialBoardsListerTimer.purge();
}
}

View File

@ -0,0 +1,83 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.discoverers.network;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.discoverers.NetworkDiscovery;
import processing.app.helpers.NetUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.*;
public class BoardReachabilityFilter extends TimerTask {
private final NetworkDiscovery networkDiscovery;
public BoardReachabilityFilter(NetworkDiscovery networkDiscovery) {
this.networkDiscovery = networkDiscovery;
}
public void start(Timer timer) {
timer.schedule(this, 0, 3000);
}
@Override
public void run() {
List<BoardPort> boardPorts = networkDiscovery.getBoardPortsDiscoveredWithJmDNS();
Iterator<BoardPort> boardPortIterator = boardPorts.iterator();
while (boardPortIterator.hasNext()) {
try {
BoardPort board = boardPortIterator.next();
InetAddress inetAddress = InetAddress.getByName(board.getAddress());
int broadcastedPort = Integer.valueOf(board.getPrefs().get("port"));
List<Integer> ports = new LinkedList<Integer>();
ports.add(broadcastedPort);
//dirty code: allows non up to date yuns to be discovered. Newer yuns will broadcast port 22
if (broadcastedPort == 80) {
ports.add(0, 22);
}
boolean reachable = NetUtils.isReachable(inetAddress, ports);
if (!reachable) {
boardPortIterator.remove();
}
} catch (UnknownHostException e) {
boardPortIterator.remove();
}
}
networkDiscovery.setReachableBoardPorts(boardPorts);
}
}

View File

@ -0,0 +1,115 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package cc.arduino.packages.discoverers.serial;
import cc.arduino.packages.BoardPort;
import cc.arduino.packages.discoverers.SerialDiscovery;
import processing.app.BaseNoGui;
import processing.app.Platform;
import processing.app.Serial;
import processing.app.debug.TargetBoard;
import processing.app.helpers.PreferencesMap;
import java.util.*;
public class SerialBoardsLister extends TimerTask {
private static final int MAX_TIME_AWAITING_FOR_PACKAGES = 5000;
private final SerialDiscovery serialDiscovery;
public SerialBoardsLister(SerialDiscovery serialDiscovery) {
this.serialDiscovery = serialDiscovery;
}
public void start(Timer timer) {
timer.schedule(this, 0, 3000);
}
@Override
public void run() {
int sleptFor = 0;
while (BaseNoGui.packages == null && sleptFor <= MAX_TIME_AWAITING_FOR_PACKAGES) {
try {
Thread.sleep(1000);
sleptFor += 1000;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
Platform platform = BaseNoGui.getPlatform();
if (platform == null) {
return;
}
List<BoardPort> boardPorts = new LinkedList<BoardPort>();
List<String> ports = Serial.list();
String devicesListOutput = null;
if (!ports.isEmpty()) {
devicesListOutput = platform.preListAllCandidateDevices();
}
for (String port : ports) {
Map<String, Object> boardData = platform.resolveDeviceAttachedTo(port, BaseNoGui.packages, devicesListOutput);
BoardPort boardPort = new BoardPort();
boardPort.setAddress(port);
boardPort.setProtocol("serial");
String label = port;
PreferencesMap prefs = new PreferencesMap();
if (boardData != null) {
prefs.put("vid", boardData.get("vid").toString());
prefs.put("pid", boardData.get("pid").toString());
TargetBoard board = (TargetBoard) boardData.get("board");
if (board != null) {
String boardName = board.getName();
if (boardName != null) {
label += " (" + boardName + ")";
}
boardPort.setBoardName(boardName);
}
}
boardPort.setLabel(label);
boardPort.setPrefs(prefs);
boardPorts.add(boardPort);
}
serialDiscovery.setSerialBoardPorts(boardPorts);
}
}

View File

@ -119,7 +119,10 @@ public class SSHUploader extends Uploader {
private boolean runAVRDude(SSH ssh) throws IOException, JSchException {
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
PreferencesMap prefs = PreferencesData.getMap();
prefs.putAll(BaseNoGui.getBoardPreferences());
PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences();
if (boardPreferences != null) {
prefs.putAll(boardPreferences);
}
prefs.putAll(targetPlatform.getTool(prefs.get("upload.tool")));
String additionalParams = verbose ? prefs.get("upload.params.verbose") : prefs.get("upload.params.quiet");

View File

@ -60,7 +60,10 @@ public class SerialUploader extends Uploader {
// FIXME: Preferences should be reorganized
TargetPlatform targetPlatform = BaseNoGui.getTargetPlatform();
PreferencesMap prefs = PreferencesData.getMap();
prefs.putAll(BaseNoGui.getBoardPreferences());
PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences();
if (boardPreferences != null) {
prefs.putAll(boardPreferences);
}
String tool = prefs.getOrExcept("upload.tool");
if (tool.contains(":")) {
String[] split = tool.split(":", 2);
@ -116,7 +119,7 @@ public class SerialUploader extends Uploader {
if (verbose)
System.out.println(
I18n.format(_("Forcing reset using 1200bps open/close on port {0}"), uploadPort));
Serial.touchPort(uploadPort, 1200);
Serial.touchForCDCReset(uploadPort);
}
Thread.sleep(400);
if (waitForUploadPort) {
@ -242,13 +245,16 @@ public class SerialUploader extends Uploader {
}
PreferencesMap prefs = PreferencesData.getMap();
prefs.putAll(BaseNoGui.getBoardPreferences());
PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences();
if (boardPreferences != null) {
prefs.putAll(boardPreferences);
}
PreferencesMap programmerPrefs = targetPlatform.getProgrammer(programmer);
if (programmerPrefs == null)
throw new RunnerException(
_("Please select a programmer from Tools->Programmer menu"));
prefs.putAll(targetPlatform.getTool(programmerPrefs.getOrExcept("program.tool")));
prefs.putAll(programmerPrefs);
prefs.putAll(targetPlatform.getTool(prefs.getOrExcept("program.tool")));
prefs.put("build.path", buildPath);
prefs.put("build.project_name", className);
@ -295,7 +301,10 @@ public class SerialUploader extends Uploader {
// Build configuration for the current programmer
PreferencesMap prefs = PreferencesData.getMap();
prefs.putAll(BaseNoGui.getBoardPreferences());
PreferencesMap boardPreferences = BaseNoGui.getBoardPreferences();
if (boardPreferences != null) {
prefs.putAll(boardPreferences);
}
prefs.putAll(programmerPrefs);
// Create configuration for bootloader tool

View File

@ -0,0 +1,303 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.utils;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.ArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import processing.app.I18n;
import processing.app.Platform;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
import static processing.app.I18n._;
public class ArchiveExtractor {
private final Platform platform;
public ArchiveExtractor(Platform platform) {
assert platform != null;
this.platform = platform;
}
/**
* Extract <b>source</b> into <b>destFolder</b>. <b>source</b> file archive
* format is autodetected from file extension.
*
* @param archiveFile
* @param destFolder
* @throws IOException
*/
public void extract(File archiveFile, File destFolder) throws IOException, InterruptedException {
extract(archiveFile, destFolder, 0);
}
/**
* Extract <b>source</b> into <b>destFolder</b>. <b>source</b> file archive
* format is autodetected from file extension.
*
* @param archiveFile Archive file to extract
* @param destFolder Destination folder
* @param stripPath Number of path elements to strip from the paths contained in the
* archived files
* @throws IOException
*/
public void extract(File archiveFile, File destFolder, int stripPath) throws IOException, InterruptedException {
extract(archiveFile, destFolder, stripPath, false);
}
public void extract(File archiveFile, File destFolder, int stripPath, boolean overwrite) throws IOException, InterruptedException {
// Folders timestamps must be set at the end of archive extraction
// (because creating a file in a folder alters the folder's timestamp)
Map<File, Long> foldersTimestamps = new HashMap<File, Long>();
ArchiveInputStream in = null;
try {
// Create an ArchiveInputStream with the correct archiving algorithm
if (archiveFile.getName().endsWith("tar.bz2")) {
in = new TarArchiveInputStream(new BZip2CompressorInputStream(new FileInputStream(archiveFile)));
} else if (archiveFile.getName().endsWith("zip")) {
in = new ZipArchiveInputStream(new FileInputStream(archiveFile));
} else if (archiveFile.getName().endsWith("tar.gz")) {
in = new TarArchiveInputStream(new GzipCompressorInputStream(new FileInputStream(archiveFile)));
} else if (archiveFile.getName().endsWith("tar")) {
in = new TarArchiveInputStream(new FileInputStream(archiveFile));
} else {
throw new IOException("Archive format not supported.");
}
String pathPrefix = "";
Map<File, File> hardLinks = new HashMap<File, File>();
Map<File, Integer> hardLinksMode = new HashMap<File, Integer>();
Map<File, String> symLinks = new HashMap<File, String>();
Map<File, Long> symLinksModifiedTimes = new HashMap<File, Long>();
// Cycle through all the archive entries
while (true) {
ArchiveEntry entry = in.getNextEntry();
if (entry == null) {
break;
}
// Extract entry info
long size = entry.getSize();
String name = entry.getName();
boolean isDirectory = entry.isDirectory();
boolean isLink = false;
boolean isSymLink = false;
String linkName = null;
Integer mode = null;
long modifiedTime = entry.getLastModifiedDate().getTime();
{
// Skip MacOSX metadata
// http://superuser.com/questions/61185/why-do-i-get-files-like-foo-in-my-tarball-on-os-x
int slash = name.lastIndexOf('/');
if (slash == -1) {
if (name.startsWith("._")) {
continue;
}
} else {
if (name.substring(slash + 1).startsWith("._")) {
continue;
}
}
}
// Skip git metadata
// http://www.unix.com/unix-for-dummies-questions-and-answers/124958-file-pax_global_header-means-what.html
if (name.contains("pax_global_header")) {
continue;
}
if (entry instanceof TarArchiveEntry) {
TarArchiveEntry tarEntry = (TarArchiveEntry) entry;
mode = tarEntry.getMode();
isLink = tarEntry.isLink();
isSymLink = tarEntry.isSymbolicLink();
linkName = tarEntry.getLinkName();
}
// On the first archive entry, if requested, detect the common path
// prefix to be stripped from filenames
if (stripPath > 0 && pathPrefix.isEmpty()) {
int slash = 0;
while (stripPath > 0) {
slash = name.indexOf("/", slash);
if (slash == -1) {
throw new IOException("Invalid archive: it must contains a single root folder");
}
slash++;
stripPath--;
}
pathPrefix = name.substring(0, slash);
}
// Strip the common path prefix when requested
if (!name.startsWith(pathPrefix)) {
throw new IOException("Invalid archive: it must contains a single root folder while file " + name + " is outside " + pathPrefix);
}
name = name.substring(pathPrefix.length());
if (name.isEmpty()) {
continue;
}
File outputFile = new File(destFolder, name);
File outputLinkedFile = null;
if (isLink) {
if (!linkName.startsWith(pathPrefix)) {
throw new IOException("Invalid archive: it must contains a single root folder while file " + linkName + " is outside " + pathPrefix);
}
linkName = linkName.substring(pathPrefix.length());
outputLinkedFile = new File(destFolder, linkName);
}
if (isSymLink) {
// Symbolic links are referenced with relative paths
outputLinkedFile = new File(linkName);
if (outputLinkedFile.isAbsolute()) {
System.err.println(I18n.format(_("Warning: file {0} links to an absolute path {1}"), outputFile, outputLinkedFile));
System.err.println();
}
}
// Safety check
if (isDirectory) {
if (outputFile.isFile() && !overwrite) {
throw new IOException("Can't create folder " + outputFile + ", a file with the same name exists!");
}
} else {
// - isLink
// - isSymLink
// - anything else
if (outputFile.exists() && !overwrite) {
throw new IOException("Can't extract file " + outputFile + ", file already exists!");
}
}
// Extract the entry
if (isDirectory) {
if (!outputFile.exists() && !outputFile.mkdirs()) {
throw new IOException("Could not create folder: " + outputFile);
}
foldersTimestamps.put(outputFile, modifiedTime);
} else if (isLink) {
hardLinks.put(outputFile, outputLinkedFile);
hardLinksMode.put(outputFile, mode);
} else if (isSymLink) {
symLinks.put(outputFile, linkName);
symLinksModifiedTimes.put(outputFile, modifiedTime);
} else {
// Create the containing folder if not exists
if (!outputFile.getParentFile().isDirectory()) {
outputFile.getParentFile().mkdirs();
}
copyStreamToFile(in, size, outputFile);
outputFile.setLastModified(modifiedTime);
}
// Set file/folder permission
if (mode != null && !isSymLink && outputFile.exists()) {
platform.chmod(outputFile, mode);
}
}
for (Map.Entry<File, File> entry : hardLinks.entrySet()) {
if (entry.getKey().exists() && overwrite) {
entry.getKey().delete();
}
platform.link(entry.getValue(), entry.getKey());
Integer mode = hardLinksMode.get(entry.getKey());
if (mode != null) {
platform.chmod(entry.getKey(), mode);
}
}
for (Map.Entry<File, String> entry : symLinks.entrySet()) {
if (entry.getKey().exists() && overwrite) {
entry.getKey().delete();
}
platform.symlink(entry.getValue(), entry.getKey());
entry.getKey().setLastModified(symLinksModifiedTimes.get(entry.getKey()));
}
} finally {
if (in != null) {
in.close();
}
}
// Set folders timestamps
for (File folder : foldersTimestamps.keySet()) {
folder.setLastModified(foldersTimestamps.get(folder));
}
}
private static void copyStreamToFile(InputStream in, long size, File outputFile) throws IOException {
FileOutputStream fos = null;
try {
fos = new FileOutputStream(outputFile);
// if size is not available, copy until EOF...
if (size == -1) {
byte buffer[] = new byte[4096];
int length;
while ((length = in.read(buffer)) != -1) {
fos.write(buffer, 0, length);
}
return;
}
// ...else copy just the needed amount of bytes
byte buffer[] = new byte[4096];
while (size > 0) {
int length = in.read(buffer);
if (length <= 0) {
throw new IOException("Error while extracting file " + outputFile.getAbsolutePath());
}
fos.write(buffer, 0, length);
size -= length;
}
} finally {
if (fos != null) {
fos.close();
}
}
}
}

View File

@ -0,0 +1,76 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class FileHash {
/**
* Calculate a message digest of a file using the algorithm specified. The
* result is a string containing the algorithm name followed by ":" and by the
* resulting hash in hex.
*
* @param file
* @param algorithm For example "SHA-256"
* @return The algorithm followed by ":" and the hash, for example:<br />
* "SHA-256:ee6796513086080cca078cbb383f543c5e508b647a71c9d6f39b7bca41071883"
* @throws IOException
* @throws NoSuchAlgorithmException
*/
public static String hash(File file, String algorithm) throws IOException, NoSuchAlgorithmException {
FileInputStream in = null;
try {
in = new FileInputStream(file);
byte buff[] = new byte[10240];
MessageDigest digest = MessageDigest.getInstance(algorithm);
while (in.available() > 0) {
int read = in.read(buff);
digest.update(buff, 0, read);
}
byte[] hash = digest.digest();
String res = "";
for (byte b : hash) {
int c = b & 0xFF;
if (c < 0x10)
res += "0";
res += Integer.toHexString(c);
}
return algorithm + ":" + res;
} finally {
if (in != null) {
in.close();
}
}
}
}

View File

@ -0,0 +1,74 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.utils;
public class MultiStepProgress implements Progress {
private final double steps;
private double step;
private double stepProgress;
String status;
public MultiStepProgress(int _steps) {
steps = _steps;
step = 0.0;
stepProgress = 0.0;
}
public double getGlobalProgress() {
return (step + stepProgress) / steps;
}
public void stepDone() {
step += 100.0;
setProgress(0.0);
}
@Override
public void setProgress(double progress) {
stepProgress = progress;
}
@Override
public void setStatus(String _status) {
status = _status;
}
@Override
public double getProgress() {
return getGlobalProgress();
}
@Override
public String getStatus() {
return status;
}
}

View File

@ -0,0 +1,41 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.utils;
public interface Progress {
void setProgress(double progress);
double getProgress();
void setStatus(String _status);
String getStatus();
}

View File

@ -0,0 +1,17 @@
package cc.arduino.utils;
import java.util.Comparator;
public class ReverseComparator<T> implements Comparator<T> {
private final Comparator<T> orig;
public ReverseComparator(Comparator<T> orig) {
this.orig = orig;
}
@Override
public int compare(T t, T t1) {
return -1 * orig.compare(t, t1);
}
}

View File

@ -0,0 +1,255 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package cc.arduino.utils.network;
import org.apache.commons.codec.binary.Base64;
import processing.app.PreferencesData;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.Observable;
public class FileDownloader extends Observable {
public enum Status {
CONNECTING, //
CONNECTION_TIMEOUT_ERROR, //
DOWNLOADING, //
COMPLETE, //
CANCELLED, //
ERROR, //
}
private Status status;
private long initialSize;
private Long downloadSize = null;
private long downloaded;
private final URL downloadUrl;
private final File outputFile;
private InputStream stream = null;
private Exception error;
public FileDownloader(URL url, File file) {
downloadUrl = url;
outputFile = file;
downloaded = 0;
initialSize = 0;
}
public long getInitialSize() {
return initialSize;
}
public Long getDownloadSize() {
return downloadSize;
}
public void setDownloadSize(Long downloadSize) {
this.downloadSize = downloadSize;
setChanged();
notifyObservers();
}
public long getDownloaded() {
return downloaded;
}
private void setDownloaded(long downloaded) {
this.downloaded = downloaded;
setChanged();
notifyObservers();
}
public float getProgress() {
if (downloadSize == null)
return 0;
if (downloadSize == 0)
return 100;
return ((float) downloaded / downloadSize) * 100;
}
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
setChanged();
notifyObservers();
}
public void download() throws InterruptedException {
RandomAccessFile file = null;
try {
// Open file and seek to the end of it
file = new RandomAccessFile(outputFile, "rw");
initialSize = file.length();
file.seek(initialSize);
setStatus(Status.CONNECTING);
System.getProperties().remove("http.proxyHost");
System.getProperties().remove("http.proxyPort");
System.getProperties().remove("https.proxyHost");
System.getProperties().remove("https.proxyPort");
System.getProperties().remove("http.proxyUser");
System.getProperties().remove("http.proxyPassword");
if (PreferencesData.has("proxy.http.server") && PreferencesData.get("proxy.http.server") != null && !PreferencesData.get("proxy.http.server").equals("")) {
System.getProperties().put("http.proxyHost", PreferencesData.get("proxy.http.server"));
System.getProperties().put("http.proxyPort", PreferencesData.get("proxy.http.port"));
}
if (PreferencesData.has("proxy.https.server") && PreferencesData.get("proxy.https.server") != null && !PreferencesData.get("proxy.https.server").equals("")) {
System.getProperties().put("https.proxyHost", PreferencesData.get("proxy.https.server"));
System.getProperties().put("https.proxyPort", PreferencesData.get("proxy.https.port"));
}
if (PreferencesData.has("proxy.user") && PreferencesData.get("proxy.user") != null && !PreferencesData.get("proxy.user").equals("")) {
System.getProperties().put("http.proxyUser", PreferencesData.get("proxy.user"));
System.getProperties().put("http.proxyPassword", PreferencesData.get("proxy.password"));
System.getProperties().put("https.proxyUser", PreferencesData.get("proxy.user"));
System.getProperties().put("https.proxyPassword", PreferencesData.get("proxy.password"));
}
HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
if (downloadUrl.getUserInfo() != null) {
String auth = "Basic " + new String(new Base64().encode(downloadUrl.getUserInfo().getBytes()));
connection.setRequestProperty("Authorization", auth);
}
connection.setRequestProperty("Range", "bytes=" + initialSize + "-");
connection.setConnectTimeout(5000);
setDownloaded(0);
// Connect
connection.connect();
int resp = connection.getResponseCode();
if (resp == HttpURLConnection.HTTP_MOVED_PERM || resp == HttpURLConnection.HTTP_MOVED_TEMP) {
String newUrl = connection.getHeaderField("Location");
// open the new connnection again
connection = (HttpURLConnection) new URL(newUrl).openConnection();
if (downloadUrl.getUserInfo() != null) {
String auth = "Basic " + new String(new Base64().encode(downloadUrl.getUserInfo().getBytes()));
connection.setRequestProperty("Authorization", auth);
}
connection.setRequestProperty("Range", "bytes=" + initialSize + "-");
connection.setConnectTimeout(5000);
connection.connect();
resp = connection.getResponseCode();
}
if (resp < 200 || resp >= 300) {
throw new IOException("Recevied invalid http status code from server: " + resp);
}
// Check for valid content length.
long len = connection.getContentLength();
if (len >= 0) {
setDownloadSize(len);
}
setStatus(Status.DOWNLOADING);
synchronized (this) {
stream = connection.getInputStream();
}
byte buffer[] = new byte[10240];
while (status == Status.DOWNLOADING) {
int read = stream.read(buffer);
if (read == -1)
break;
file.write(buffer, 0, read);
setDownloaded(getDownloaded() + read);
if (Thread.interrupted())
throw new InterruptedException();
}
if (getDownloadSize() != null) {
if (getDownloaded() < getDownloadSize())
throw new Exception("Incomplete download");
}
setStatus(Status.COMPLETE);
} catch (InterruptedException e) {
setStatus(Status.CANCELLED);
// lets InterruptedException go up to the caller
throw e;
} catch (SocketTimeoutException e) {
setStatus(Status.CONNECTION_TIMEOUT_ERROR);
setError(e);
} catch (Exception e) {
setStatus(Status.ERROR);
setError(e);
} finally {
if (file != null) {
try {
file.close();
} catch (Exception e) {
//ignore
}
}
synchronized (this) {
if (stream != null) {
try {
stream.close();
} catch (Exception e) {
//ignore
}
}
}
}
}
private void setError(Exception e) {
error = e;
}
public Exception getError() {
return error;
}
public boolean isCompleted() {
return status == Status.COMPLETE;
}
}

View File

@ -1,45 +1,53 @@
package processing.app;
import static processing.app.I18n._;
import cc.arduino.contributions.SignatureVerificationFailedException;
import cc.arduino.contributions.libraries.LibrariesIndexer;
import cc.arduino.contributions.packages.ContributedTool;
import cc.arduino.contributions.packages.ContributionsIndexer;
import cc.arduino.files.DeleteFilesOnShutdown;
import cc.arduino.packages.DiscoveryManager;
import cc.arduino.packages.Uploader;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.apache.commons.logging.impl.NoOpLog;
import processing.app.debug.Compiler;
import processing.app.debug.*;
import processing.app.helpers.*;
import processing.app.helpers.filefilters.OnlyDirs;
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
import processing.app.legacy.PApplet;
import processing.app.packages.LibraryList;
import processing.app.packages.UserLibrary;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.*;
import java.net.URISyntaxException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.logging.impl.LogFactoryImpl;
import org.apache.commons.logging.impl.NoOpLog;
import cc.arduino.packages.DiscoveryManager;
import cc.arduino.packages.Uploader;
import processing.app.debug.Compiler;
import processing.app.debug.TargetBoard;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
import processing.app.debug.TargetPlatformException;
import processing.app.helpers.BasicUserNotifier;
import processing.app.helpers.CommandlineParser;
import processing.app.helpers.OSUtils;
import processing.app.helpers.PreferencesMap;
import processing.app.helpers.UserNotifier;
import processing.app.helpers.filefilters.OnlyDirs;
import processing.app.helpers.filefilters.OnlyFilesWithExtension;
import processing.app.legacy.PApplet;
import processing.app.packages.Library;
import processing.app.packages.LibraryList;
import static processing.app.I18n._;
public class BaseNoGui {
/** Version string to be used for build */
public static final int REVISION = 10601;
public static final int REVISION = 10605;
/** Extended version string displayed on GUI */
static String VERSION_NAME = "1.6.1";
public static final String VERSION_NAME = "1.6.5";
public static final String VERSION_NAME_LONG;
static {
String versionNameLong = VERSION_NAME;
File hourlyBuildTxt = new File(getContentFile("lib"), "hourlyBuild.txt");
if (hourlyBuildTxt.exists() && hourlyBuildTxt.canRead()) {
versionNameLong += " Hourly Build";
try {
versionNameLong += " " + FileUtils.readFileToString(hourlyBuildTxt).trim();
} catch (IOException e) {
//noop
}
}
VERSION_NAME_LONG = versionNameLong;
}
static File buildFolder;
@ -54,11 +62,12 @@ public class BaseNoGui {
static private File toolsFolder;
// maps #included files to their library folder
public static Map<String, Library> importToLibraryTable;
public static Map<String, LibraryList> importToLibraryTable;
// maps library name to their library folder
static private LibraryList libraries;
// XXX: Remove this field
static private List<File> librariesFolders;
static UserNotifier notifier = new BasicUserNotifier();
@ -68,9 +77,11 @@ public class BaseNoGui {
static Platform platform;
static File portableFolder = null;
static final String portableSketchbookFolder = "sketchbook";
public static ContributionsIndexer indexer;
static LibrariesIndexer librariesIndexer;
// Returns a File object for the given pathname. If the pathname
// is not absolute, it is interpreted relative to the current
// directory when starting the IDE (which is not the same as the
@ -139,7 +150,7 @@ public class BaseNoGui {
//File folder = new File(getTempFolder(), "build");
//if (!folder.exists()) folder.mkdirs();
buildFolder = createTempFolder("build");
buildFolder.deleteOnExit();
DeleteFilesOnShutdown.add(buildFolder);
}
}
return buildFolder;
@ -238,13 +249,6 @@ public class BaseNoGui {
return librariesFolders;
}
/**
* Return an InputStream for a file inside the Processing lib folder.
*/
static public InputStream getLibStream(String filename) throws IOException {
return new FileInputStream(new File(getContentFile("lib"), filename));
}
static public Platform getPlatform() {
return platform;
}
@ -403,9 +407,8 @@ public class BaseNoGui {
}
static public LibraryList getUserLibs() {
if (libraries == null)
return new LibraryList();
return libraries.filterLibrariesInSubfolder(getSketchbookFolder());
LibraryList libs = BaseNoGui.librariesIndexer.getInstalledLibraries();
return libs.filterLibrariesInSubfolder(getSketchbookFolder());
}
/**
@ -421,7 +424,7 @@ public class BaseNoGui {
return list;
}
static public void init(String[] args) {
static public void init(String[] args) throws Exception {
getPlatform().init();
String sketchbookPath = getSketchbookPath();
@ -508,7 +511,7 @@ public class BaseNoGui {
// - calls Sketch.build(verbose=false) that calls Sketch.ensureExistence(), set progressListener and calls Compiler.build()
// - calls Sketch.upload() (see later...)
if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null);
String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild());
String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild(), false);
if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null);
showMessage(_("Done compiling"), _("Done compiling"));
@ -553,7 +556,7 @@ public class BaseNoGui {
// if (!data.getFolder().exists()) showError(...);
// String ... = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, verbose);
if (!data.getFolder().exists()) showError(_("No sketch"), _("Can't find the sketch in the specified path"), null);
String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild());
String suggestedClassName = Compiler.build(data, tempBuildFolder.getAbsolutePath(), tempBuildFolder, null, parser.isDoVerboseBuild(), false);
if (suggestedClassName == null) showError(_("Error while verifying"), _("An error occurred while verifying the sketch"), null);
showMessage(_("Done compiling"), _("Done compiling"));
} catch (Exception e) {
@ -582,13 +585,77 @@ public class BaseNoGui {
Logger.getLogger("javax.jmdns").setLevel(Level.OFF);
}
static public void initPackages() {
static public void initPackages() throws Exception {
indexer = new ContributionsIndexer(BaseNoGui.getSettingsFolder());
File indexFile = indexer.getIndexFile("package_index.json");
File defaultPackageJsonFile = new File(getContentFile("dist"), "package_index.json");
if (!indexFile.isFile() || (defaultPackageJsonFile.isFile() && defaultPackageJsonFile.lastModified() > indexFile.lastModified())) {
FileUtils.copyFile(defaultPackageJsonFile, indexFile);
} else if (!indexFile.isFile()) {
// Otherwise create an empty packages index
FileOutputStream out = null;
try {
out = new FileOutputStream(indexFile);
out.write("{ \"packages\" : [ ] }".getBytes());
out.close();
} finally {
if (out != null) {
out.close();
}
}
}
File indexSignatureFile = indexer.getIndexFile("package_index.json.sig");
File defaultPackageJsonSignatureFile = new File(getContentFile("dist"), "package_index.json.sig");
if (!indexSignatureFile.isFile() || (defaultPackageJsonSignatureFile.isFile() && defaultPackageJsonSignatureFile.lastModified() > indexSignatureFile.lastModified())) {
FileUtils.copyFile(defaultPackageJsonSignatureFile, indexSignatureFile);
}
try {
indexer.parseIndex();
} catch (JsonProcessingException e) {
FileUtils.deleteIfExists(indexFile);
FileUtils.deleteIfExists(indexSignatureFile);
throw e;
} catch (SignatureVerificationFailedException e) {
FileUtils.deleteIfExists(indexFile);
FileUtils.deleteIfExists(indexSignatureFile);
throw e;
}
indexer.syncWithFilesystem(getHardwareFolder());
packages = new HashMap<String, TargetPackage>();
loadHardware(getHardwareFolder());
loadHardware(getSketchbookHardwareFolder());
if (packages.size() == 0) {
System.out.println(_("No valid configured cores found! Exiting..."));
System.exit(3);
loadContributedHardware(indexer);
createToolPreferences(indexer);
librariesIndexer = new LibrariesIndexer(BaseNoGui.getSettingsFolder());
File librariesIndexFile = librariesIndexer.getIndexFile();
if (!librariesIndexFile.isFile()) {
File defaultLibraryJsonFile = new File(getContentFile("dist"), "library_index.json");
if (defaultLibraryJsonFile.isFile()) {
FileUtils.copyFile(defaultLibraryJsonFile, librariesIndexFile);
} else {
FileOutputStream out = null;
try {
// Otherwise create an empty packages index
out = new FileOutputStream(librariesIndexFile);
out.write("{ \"libraries\" : [ ] }".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
out.close();
}
}
}
}
try {
librariesIndexer.parseIndex();
} catch (JsonProcessingException e) {
FileUtils.deleteIfExists(librariesIndexFile);
throw e;
}
}
@ -649,9 +716,9 @@ public class BaseNoGui {
File subfolder = new File(folder, target);
try {
packages.put(target, new TargetPackage(target, subfolder));
packages.put(target, new LegacyTargetPackage(target, subfolder));
} catch (TargetPlatformException e) {
System.out.println("WARNING: Error loading hardware folder " + target);
System.out.println("WARNING: Error loading hardware folder " + new File(folder, target));
System.out.println(" " + e.getMessage());
}
}
@ -670,6 +737,8 @@ public class BaseNoGui {
if (args.length == 0)
showError(_("No parameters"), _("No command line parameters found"), null);
Runtime.getRuntime().addShutdownHook(new Thread(DeleteFilesOnShutdown.INSTANCE));
initPlatform();
initPortableFolder();
@ -683,9 +752,10 @@ public class BaseNoGui {
examplesFolder = getContentFile("examples");
toolsFolder = getContentFile("tools");
librariesFolders = new ArrayList<File>();
// Add IDE libraries folder
librariesFolders.add(getContentFile("libraries"));
// Add library folder for the current selected platform
TargetPlatform targetPlatform = getTargetPlatform();
if (targetPlatform != null) {
String core = getBoardPreferences().get("build.core", "arduino");
@ -694,35 +764,69 @@ public class BaseNoGui {
TargetPlatform referencedPlatform = getTargetPlatform(referencedCore, targetPlatform.getId());
if (referencedPlatform != null) {
File referencedPlatformFolder = referencedPlatform.getFolder();
librariesFolders.add(new File(referencedPlatformFolder, "libraries"));
// Add libraries folder for the referenced platform
File folder = new File(referencedPlatformFolder, "libraries");
librariesFolders.add(folder);
}
}
File platformFolder = targetPlatform.getFolder();
librariesFolders.add(new File(platformFolder, "libraries"));
librariesFolders.add(getSketchbookLibrariesFolder());
// Add libraries folder for the selected platform
File folder = new File(platformFolder, "libraries");
librariesFolders.add(folder);
}
// Add libraries folder for the sketchbook
librariesFolders.add(getSketchbookLibrariesFolder());
// Scan for libraries in each library folder.
// Libraries located in the latest folders on the list can override
// other libraries with the same name.
try {
scanAndUpdateLibraries(librariesFolders);
} catch (IOException e) {
showWarning(_("Error"), _("Error loading libraries"), e);
}
BaseNoGui.librariesIndexer.setSketchbookLibrariesFolder(getSketchbookLibrariesFolder());
BaseNoGui.librariesIndexer.setLibrariesFolders(librariesFolders);
BaseNoGui.librariesIndexer.rescanLibraries();
populateImportToLibraryTable();
}
static protected void loadContributedHardware(ContributionsIndexer indexer) throws TargetPlatformException {
for (TargetPackage pack : indexer.createTargetPackages()) {
packages.put(pack.getId(), pack);
}
}
static private void createToolPreferences(ContributionsIndexer indexer) {
// Remove previous runtime preferences
final String prefix = "runtime.tools.";
PreferencesData.removeAllKeysWithPrefix(prefix);
for (ContributedTool tool : indexer.getInstalledTools()) {
File installedFolder = tool.getDownloadableContribution().getInstalledFolder();
if (installedFolder != null) {
PreferencesData.set(prefix + tool.getName() + ".path", installedFolder.getAbsolutePath());
PreferencesData.set(prefix + tool.getName() + "-" + tool.getVersion() + ".path", installedFolder.getAbsolutePath());
}
}
}
static public void populateImportToLibraryTable() {
// Populate importToLibraryTable
importToLibraryTable = new HashMap<String, Library>();
for (Library lib : getLibraries()) {
// Populate importToLibraryTable. Each header filename maps to
// a list of libraries. Compiler.java will use only the first
// library on each list. The others are used only to advise
// user of ambiguously matched and duplicate libraries.
importToLibraryTable = new HashMap<String, LibraryList>();
for (UserLibrary lib : librariesIndexer.getInstalledLibraries()) {
try {
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
for (String header : headers) {
Library old = importToLibraryTable.get(header);
if (old != null) {
LibraryList list = importToLibraryTable.get(header);
if (list == null) {
// This is the first library found with this header
list = new LibraryList();
list.addFirst(lib);
importToLibraryTable.put(header, list);
} else {
UserLibrary old = list.peekFirst();
boolean useThisLib = true;
// This is the case where 2 libraries have a .h header
// with the same name. We must decide which library to
// use when a sketch has #include "name.h"
@ -737,61 +841,84 @@ public class BaseNoGui {
// for "libName", then for "oldName".
//
String name = header.substring(0, header.length() - 2); // name without ".h"
String oldName = old.getFolder().getName(); // just the library folder name
String libName = lib.getFolder().getName(); // just the library folder name
String oldName = old.getInstalledFolder().getName(); // just the library folder name
String libName = lib.getInstalledFolder().getName(); // just the library folder name
//System.out.println("name conflict: " + name);
//System.out.println(" old = " + oldName + " -> " + old.getFolder().getPath());
//System.out.println(" new = " + libName + " -> " + lib.getFolder().getPath());
//System.out.println(" old = " + oldName + " -> " + old.getInstalledFolder().getPath());
//System.out.println(" new = " + libName + " -> " + lib.getInstalledFolder().getPath());
String name_lc = name.toLowerCase();
String oldName_lc = oldName.toLowerCase();
String libName_lc = libName.toLowerCase();
// always favor a perfect name match
if (libName.equals(name)) {
} else if (oldName.equals(name)) {
continue;
useThisLib = false;
// check for "-master" appended (zip file from github)
} else if (libName.equals(name+"-master")) {
} else if (oldName.equals(name+"-master")) {
continue;
useThisLib = false;
// next, favor a match with other stuff appended
} else if (libName.startsWith(name)) {
} else if (oldName.startsWith(name)) {
continue;
useThisLib = false;
// otherwise, favor a match with stuff prepended
} else if (libName.endsWith(name)) {
} else if (oldName.endsWith(name)) {
continue;
useThisLib = false;
// as a last resort, match if stuff prepended and appended
} else if (libName.contains(name)) {
} else if (oldName.contains(name)) {
continue;
useThisLib = false;
// repeat all the above tests, with case insensitive matching
} else if (libName_lc.equals(name_lc)) {
} else if (oldName_lc.equals(name_lc)) {
continue;
useThisLib = false;
} else if (libName_lc.equals(name_lc+"-master")) {
} else if (oldName_lc.equals(name_lc+"-master")) {
continue;
useThisLib = false;
} else if (libName_lc.startsWith(name_lc)) {
} else if (oldName_lc.startsWith(name_lc)) {
continue;
useThisLib = false;
} else if (libName_lc.endsWith(name_lc)) {
} else if (oldName_lc.endsWith(name_lc)) {
continue;
useThisLib = false;
} else if (libName_lc.contains(name_lc)) {
} else if (oldName_lc.contains(name_lc)) {
continue;
useThisLib = false;
} else {
// none of these tests matched, so just default to "libName".
}
if (useThisLib) {
list.addFirst(lib);
} else {
list.addLast(lib);
}
}
importToLibraryTable.put(header, lib);
}
} catch (IOException e) {
showWarning(_("Error"), I18n
.format("Unable to list header files in {0}", lib.getSrcFolder()), e);
}
}
// repeat for ALL libraries, to pick up duplicates not visible normally.
// any new libraries found here are NEVER used, but they are added to the
// end of already-found headers, to allow Compiler to report them if
// the sketch tries to use them.
for (UserLibrary lib : librariesIndexer.getInstalledLibrariesWithDuplicates()) {
try {
String headers[] = headerListFromIncludePath(lib.getSrcFolder());
for (String header : headers) {
LibraryList list = importToLibraryTable.get(header);
if (list != null) {
if (!(list.hasLibrary(lib))) {
list.addLast(lib);
//System.out.println(" duplicate lib: " + lib.getInstalledFolder().getPath());
}
}
}
} catch (IOException e) {
}
}
}
static public void initParameters(String args[]) {
@ -926,49 +1053,6 @@ public class BaseNoGui {
}
}
static public void scanAndUpdateLibraries(List<File> folders) throws IOException {
libraries = scanLibraries(folders);
}
static public LibraryList scanLibraries(List<File> folders) throws IOException {
LibraryList res = new LibraryList();
for (File folder : folders)
res.addOrReplaceAll(scanLibraries(folder));
return res;
}
static public LibraryList scanLibraries(File folder) throws IOException {
LibraryList res = new LibraryList();
String list[] = folder.list(new OnlyDirs());
// if a bad folder or something like that, this might come back null
if (list == null)
return res;
for (String libName : list) {
File subfolder = new File(folder, libName);
if (!isSanitaryName(libName)) {
String mess = I18n.format(_("The library \"{0}\" cannot be used.\n"
+ "Library names must contain only basic letters and numbers.\n"
+ "(ASCII only and no spaces, and it cannot start with a number)"),
libName);
showMessage(_("Ignoring bad library name"), mess);
continue;
}
try {
Library lib = Library.create(subfolder);
// (also replace previously found libs with the same name)
if (lib != null)
res.addOrReplace(lib);
} catch (IOException e) {
System.out.println(I18n.format(_("Invalid library found in {0}: {1}"),
subfolder, e.getMessage()));
}
}
return res;
}
static public void selectBoard(TargetBoard targetBoard) {
TargetPlatform targetPlatform = targetBoard.getContainerPlatform();
TargetPackage targetPackage = targetPlatform.getContainerPackage();

View File

@ -24,11 +24,11 @@ public class I18n {
// prompt text stuff
static String PROMPT_YES;
static String PROMPT_NO;
static String PROMPT_CANCEL;
static String PROMPT_OK;
static String PROMPT_BROWSE;
public static String PROMPT_YES;
public static String PROMPT_NO;
public static String PROMPT_CANCEL;
public static String PROMPT_OK;
public static String PROMPT_BROWSE;
static protected void init(String language) throws MissingResourceException {
String[] languageParts = language.split("_");

View File

@ -21,24 +21,19 @@
*/
package processing.app;
import static processing.app.I18n._;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import javax.swing.UIManager;
import cc.arduino.packages.BoardPort;
import com.sun.jna.Library;
import com.sun.jna.Native;
import processing.app.debug.TargetBoard;
import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
import processing.app.legacy.PConstants;
import javax.swing.*;
import java.io.*;
import java.util.*;
import static processing.app.I18n._;
/**
* Used by Base for platform-specific tweaking, for instance finding the
@ -75,7 +70,7 @@ public class Platform {
}
public void init() {
public void init() throws IOException {
}
@ -169,6 +164,8 @@ public class Platform {
}
public String resolveDeviceByBoardID(Map<String, TargetPackage> packages, String boardId) {
assert packages != null;
assert boardId != null;
for (TargetPackage targetPackage : packages.values()) {
for (TargetPlatform targetPlatform : targetPackage.getPlatforms().values()) {
for (TargetBoard board : targetPlatform.getBoards().values()) {
@ -183,33 +180,6 @@ public class Platform {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
public interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary)Native.loadLibrary("c", CLibrary.class);
int setenv(String name, String value, int overwrite);
String getenv(String name);
int unsetenv(String name);
int putenv(String string);
}
public void setenv(String variable, String value) {
CLibrary clib = CLibrary.INSTANCE;
clib.setenv(variable, value, 1);
}
public String getenv(String variable) {
CLibrary clib = CLibrary.INSTANCE;
return clib.getenv(variable);
}
public int unsetenv(String variable) {
CLibrary clib = CLibrary.INSTANCE;
return clib.unsetenv(variable);
}
public String getName() {
return PConstants.platformNames[PConstants.OTHER];
}
@ -227,4 +197,39 @@ public class Platform {
public List<BoardPort> filterPorts(List<BoardPort> ports, boolean aBoolean) {
return new LinkedList<BoardPort>(ports);
}
public void fixPrefsFilePermissions(File prefsFile) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(new String[]{"chmod", "600", prefsFile.getAbsolutePath()}, null, null);
process.waitFor();
}
public List<File> postInstallScripts(File folder) {
List<File> scripts = new LinkedList<File>();
scripts.add(new File(folder, "install_script.sh"));
scripts.add(new File(folder, "post_install.sh"));
return scripts;
}
public String getOsName() {
return System.getProperty("os.name");
}
public String getOsArch() {
return System.getProperty("os.arch");
}
public void symlink(String something, File somewhere) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(new String[]{"ln", "-s", something, somewhere.getAbsolutePath()}, null, somewhere.getParentFile());
process.waitFor();
}
public void link(File something, File somewhere) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(new String[]{"ln", something.getAbsolutePath(), somewhere.getAbsolutePath()}, null, null);
process.waitFor();
}
public void chmod(File file, int mode) throws IOException, InterruptedException {
Process process = Runtime.getRuntime().exec(new String[]{"chmod", Integer.toOctalString(mode), file.getAbsolutePath()}, null, null);
process.waitFor();
}
}

View File

@ -2,6 +2,7 @@ package processing.app;
import static processing.app.I18n._;
import java.awt.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
@ -9,8 +10,10 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.Iterator;
import java.util.MissingResourceException;
import processing.app.helpers.PreferencesHelper;
import processing.app.helpers.PreferencesMap;
import processing.app.legacy.PApplet;
import processing.app.legacy.PConstants;
@ -18,7 +21,7 @@ import processing.app.legacy.PConstants;
public class PreferencesData {
static final String PREFS_FILE = "preferences.txt";
private static final String PREFS_FILE = "preferences.txt";
// data model
@ -29,18 +32,25 @@ public class PreferencesData {
static public void init(File file) {
if (file != null)
if (file != null) {
preferencesFile = file;
else
} else {
preferencesFile = BaseNoGui.getSettingsFile(PREFS_FILE);
}
try {
BaseNoGui.getPlatform().fixPrefsFilePermissions(preferencesFile);
} catch (Exception e) {
//ignore
}
// start by loading the defaults, in case something
// important was deleted from the user prefs
try {
prefs.load(BaseNoGui.getLibStream("preferences.txt"));
prefs.load(new File(BaseNoGui.getContentFile("lib"), PREFS_FILE));
} catch (IOException e) {
BaseNoGui.showError(null, _("Could not read default settings.\n" +
"You'll need to reinstall Arduino."), e);
"You'll need to reinstall Arduino."), e);
}
// set some runtime constants (not saved on preferences file)
@ -78,6 +88,10 @@ public class PreferencesData {
fixPreferences();
}
public static File getPreferencesFile() {
return preferencesFile;
}
private static void fixPreferences() {
String baud = get("serial.debug_rate");
if ("14400".equals(baud) || "28800".equals(baud)) {
@ -86,41 +100,6 @@ public class PreferencesData {
}
static public String[] loadStrings(InputStream input) {
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(input, "UTF-8"));
String lines[] = new String[100];
int lineCount = 0;
String line = null;
while ((line = reader.readLine()) != null) {
if (lineCount == lines.length) {
String temp[] = new String[lineCount << 1];
System.arraycopy(lines, 0, temp, 0, lineCount);
lines = temp;
}
lines[lineCount++] = line;
}
reader.close();
if (lineCount == lines.length) {
return lines;
}
// resize array to appropriate amount for these lines
String output[] = new String[lineCount];
System.arraycopy(lines, 0, output, 0, lineCount);
return output;
} catch (IOException e) {
e.printStackTrace();
//throw new RuntimeException("Error inside loadStrings()");
}
return null;
}
static protected void save() {
if (!doSave)
return;
@ -131,18 +110,30 @@ public class PreferencesData {
if (preferencesFile == null) return;
// Fix for 0163 to properly use Unicode when writing preferences.txt
PrintWriter writer = PApplet.createWriter(preferencesFile);
PrintWriter writer = null;
try {
writer = PApplet.createWriter(preferencesFile);
String[] keys = prefs.keySet().toArray(new String[0]);
Arrays.sort(keys);
for (String key: keys) {
if (key.startsWith("runtime."))
continue;
writer.println(key + "=" + prefs.get(key));
String[] keys = prefs.keySet().toArray(new String[0]);
Arrays.sort(keys);
for (String key : keys) {
if (key.startsWith("runtime."))
continue;
writer.println(key + "=" + prefs.get(key));
}
writer.flush();
} finally {
if (writer != null) {
writer.close();
}
}
writer.flush();
writer.close();
try {
BaseNoGui.getPlatform().fixPrefsFilePermissions(preferencesFile);
} catch (Exception e) {
//ignore
}
}
@ -194,6 +185,13 @@ public class PreferencesData {
return Integer.parseInt(get(attribute));
}
static public int getInteger(String attribute, int defaultValue) {
if (has(attribute)) {
return getInteger(attribute);
}
return defaultValue;
}
static public void setInteger(String key, int value) {
set(key, String.valueOf(value));
@ -205,10 +203,27 @@ public class PreferencesData {
return new PreferencesMap(prefs);
}
static public void removeAllKeysWithPrefix(String prefix) {
Iterator<String> keys = prefs.keySet().iterator();
while (keys.hasNext())
if (keys.next().startsWith(prefix))
keys.remove();
}
// Decide wether changed preferences will be saved. When value is
// false, Preferences.save becomes a no-op.
static public void setDoSave(boolean value)
{
doSave = value;
}
static public Font getFont(String attr) {
Font font = PreferencesHelper.getFont(prefs, attr);
if (font == null) {
String value = defaults.get(attr);
prefs.put(attr, value);
font = PreferencesHelper.getFont(prefs, attr);
}
return font;
}
}

View File

@ -88,11 +88,12 @@ public class Serial implements SerialPortEventListener {
BaseNoGui.getBoardPreferences().get("serial.disableDTR") == null);
}
public static boolean touchPort(String iname, int irate) throws SerialException {
public static boolean touchForCDCReset(String iname) throws SerialException {
SerialPort serialPort = new SerialPort(iname);
try {
serialPort.openPort();
serialPort.setParams(irate, 8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
serialPort.setParams(1200, 8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
serialPort.setDTR(false);
serialPort.closePort();
return true;
} catch (SerialPortException e) {

View File

@ -25,13 +25,7 @@ package processing.app.debug;
import static processing.app.I18n._;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@ -45,6 +39,9 @@ import cc.arduino.packages.BoardPort;
import cc.arduino.packages.Uploader;
import cc.arduino.packages.UploaderFactory;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteStreamHandler;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.PreferencesData;
@ -52,10 +49,12 @@ import processing.app.SketchCode;
import processing.app.SketchData;
import processing.app.helpers.*;
import processing.app.helpers.filefilters.OnlyDirs;
import processing.app.packages.Library;
import processing.app.packages.LibraryList;
import processing.app.preproc.PdePreprocessor;
import processing.app.legacy.PApplet;
import processing.app.packages.LegacyUserLibrary;
import processing.app.packages.UserLibrary;
import processing.app.tools.DoubleQuotedArgumentsOnWindowsCommandLine;
public class Compiler implements MessageConsumer {
@ -68,6 +67,7 @@ public class Compiler implements MessageConsumer {
private SketchData sketch;
private PreferencesMap prefs;
private boolean verbose;
private boolean saveHex;
private List<File> objectFiles;
@ -84,7 +84,7 @@ public class Compiler implements MessageConsumer {
private ProgressListener progressListener;
static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose) throws RunnerException, PreferencesMapException {
static public String build(SketchData data, String buildPath, File tempBuildFolder, ProgressListener progListener, boolean verbose, boolean save) throws RunnerException, PreferencesMapException {
if (SketchData.checkSketchFile(data.getPrimaryFile()) == null)
BaseNoGui.showError(_("Bad file selected"),
_("Bad sketch primary file or bad sketch directory structure"), null);
@ -113,9 +113,16 @@ public class Compiler implements MessageConsumer {
// compile the program. errors will happen as a RunnerException
// that will bubble up to whomever called build().
if (compiler.compile(verbose)) {
compiler.size(compiler.getBuildPreferences());
return primaryClassName;
try {
if (compiler.compile(verbose, save)) {
compiler.size(compiler.getBuildPreferences());
return primaryClassName;
}
} catch (RunnerException e) {
// when the compile fails, take this opportunity to show
// any helpful info possible before throwing the exception
compiler.adviseDuplicateLibraries();
throw e;
}
return null;
}
@ -183,6 +190,9 @@ public class Compiler implements MessageConsumer {
sketch = _sketch;
prefs = createBuildPreferences(_buildPath, _primaryClassName);
// provide access to the source tree
prefs.put("build.source.path", _sketch.getFolder().getAbsolutePath());
// Start with an empty progress listener
progressListener = new ProgressListener() {
@Override
@ -311,10 +321,10 @@ public class Compiler implements MessageConsumer {
if (maxDataSize > 0) {
System.out
.println(I18n
.format(
_("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."),
dataSize, maxDataSize, dataSize * 100 / maxDataSize,
maxDataSize - dataSize));
.format(
_("Global variables use {0} bytes ({2}%%) of dynamic memory, leaving {3} bytes for local variables. Maximum is {1} bytes."),
dataSize, maxDataSize, dataSize * 100 / maxDataSize,
maxDataSize - dataSize));
} else {
System.out.println(I18n
.format(_("Global variables use {0} bytes of dynamic memory."), dataSize));
@ -341,11 +351,16 @@ public class Compiler implements MessageConsumer {
* @return true if successful.
* @throws RunnerException Only if there's a problem. Only then.
*/
public boolean compile(boolean _verbose) throws RunnerException, PreferencesMapException {
public boolean compile(boolean _verbose, boolean _save) throws RunnerException, PreferencesMapException {
preprocess(prefs.get("build.path"));
verbose = _verbose || PreferencesData.getBoolean("build.verbose");
saveHex = _save;
sketchIsCompiled = false;
// Hook runs at Start of Compilation
runActions("hooks.prebuild", prefs);
objectFiles = new ArrayList<File>();
// 0. include paths for core + all libraries
@ -354,11 +369,15 @@ public class Compiler implements MessageConsumer {
includeFolders.add(prefs.getFile("build.core.path"));
if (prefs.getFile("build.variant.path") != null)
includeFolders.add(prefs.getFile("build.variant.path"));
for (Library lib : importedLibraries) {
if (verbose)
for (UserLibrary lib : importedLibraries) {
if (verbose) {
String legacy = "";
if (lib instanceof LegacyUserLibrary)
legacy = "(legacy)";
System.out.println(I18n
.format(_("Using library {0} in folder: {1} {2}"), lib.getName(),
lib.getFolder(), lib.isLegacy() ? "(legacy)" : ""));
lib.getInstalledFolder(), legacy));
}
includeFolders.add(lib.getSrcFolder());
}
if (verbose)
@ -370,7 +389,7 @@ public class Compiler implements MessageConsumer {
String[] overrides = prefs.get("architecture.override_check").split(",");
archs.addAll(Arrays.asList(overrides));
}
for (Library lib : importedLibraries) {
for (UserLibrary lib : importedLibraries) {
if (!lib.supportsArchitecture(archs)) {
System.err.println(I18n
.format(_("WARNING: library {0} claims to run on {1} "
@ -382,26 +401,26 @@ public class Compiler implements MessageConsumer {
}
// 1. compile the sketch (already in the buildPath)
progressListener.progress(30);
progressListener.progress(20);
compileSketch(includeFolders);
sketchIsCompiled = true;
// 2. compile the libraries, outputting .o files to: <buildPath>/<library>/
// Doesn't really use configPreferences
progressListener.progress(40);
progressListener.progress(30);
compileLibraries(includeFolders);
// 3. compile the core, outputting .o files to <buildPath> and then
// collecting them into the core.a library file.
progressListener.progress(50);
progressListener.progress(40);
compileCore();
// 4. link it all together into the .elf file
progressListener.progress(60);
progressListener.progress(50);
compileLink();
// 5. run objcopy to generate output files
progressListener.progress(75);
progressListener.progress(60);
List<String> objcopyPatterns = new ArrayList<String>();
for (String key : prefs.keySet()) {
if (key.startsWith("recipe.objcopy.") && key.endsWith(".pattern"))
@ -412,10 +431,39 @@ public class Compiler implements MessageConsumer {
runRecipe(recipe);
}
// 7. save the hex file
if (saveHex) {
progressListener.progress(80);
saveHex();
}
progressListener.progress(90);
// Hook runs at End of Compilation
runActions("hooks.postbuild", prefs);
adviseDuplicateLibraries();
return true;
}
private void adviseDuplicateLibraries() {
for (int i=0; i < importedDuplicateHeaders.size(); i++) {
System.out.println(I18n.format(_("Multiple libraries were found for \"{0}\""),
importedDuplicateHeaders.get(i)));
boolean first = true;
for (UserLibrary lib : importedDuplicateLibraries.get(i)) {
if (first) {
System.out.println(I18n.format(_(" Used: {0}"),
lib.getInstalledFolder().getPath()));
first = false;
} else {
System.out.println(I18n.format(_(" Not used: {0}"),
lib.getInstalledFolder().getPath()));
}
}
}
}
private PreferencesMap createBuildPreferences(String _buildPath,
String _primaryClassName)
throws RunnerException {
@ -647,7 +695,6 @@ public class Compiler implements MessageConsumer {
command = stringList.toArray(new String[stringList.size()]);
if (command.length == 0)
return;
int result = 0;
if (verbose) {
for (String c : command)
@ -655,30 +702,57 @@ public class Compiler implements MessageConsumer {
System.out.println();
}
Process process;
DefaultExecutor executor = new DefaultExecutor();
executor.setStreamHandler(new ExecuteStreamHandler() {
@Override
public void setProcessInputStream(OutputStream os) throws IOException {
}
@Override
public void setProcessErrorStream(InputStream is) throws IOException {
forwardToMessage(is);
}
@Override
public void setProcessOutputStream(InputStream is) throws IOException {
forwardToMessage(is);
}
private void forwardToMessage(InputStream is) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
message(line + "\n");
}
}
@Override
public void start() throws IOException {
}
@Override
public void stop() {
}
});
CommandLine commandLine = new DoubleQuotedArgumentsOnWindowsCommandLine(command[0]);
for (int i = 1; i < command.length; i++) {
commandLine.addArgument(command[i], false);
}
int result;
executor.setExitValues(null);
try {
process = ProcessUtils.exec(command);
result = executor.execute(commandLine);
} catch (IOException e) {
RunnerException re = new RunnerException(e.getMessage());
re.hideStackTrace();
throw re;
}
MessageSiphon in = new MessageSiphon(process.getInputStream(), this);
MessageSiphon err = new MessageSiphon(process.getErrorStream(), this);
// wait for the process to finish. if interrupted
// before waitFor returns, continue waiting
boolean compiling = true;
while (compiling) {
try {
in.join();
err.join();
result = process.waitFor();
//System.out.println("result is " + result);
compiling = false;
} catch (InterruptedException ignored) { }
}
executor.setExitValues(new int[0]);
// an error was queued up by message(), barf this back to compile(),
// which will barf it back to Editor. if you're having trouble
@ -720,10 +794,10 @@ public class Compiler implements MessageConsumer {
s = s.substring(0, i) + s.substring(i + (buildPath + File.separator).length());
}
}
// look for error line, which contains file name, line number,
// and at least the first line of the error message
String errorFormat = "([\\w\\d_]+.\\w+):(\\d+):\\s*error:\\s*(.*)\\s*";
String errorFormat = "(.+\\.\\w+):(\\d+)(:\\d+)*:\\s*error:\\s*(.*)\\s*";
String[] pieces = PApplet.match(s, errorFormat);
// if (pieces != null && exception == null) {
@ -732,56 +806,56 @@ public class Compiler implements MessageConsumer {
// }
if (pieces != null) {
String error = pieces[3], msg = "";
String error = pieces[pieces.length - 1], msg = "";
if (pieces[3].trim().equals("SPI.h: No such file or directory")) {
if (error.trim().equals("SPI.h: No such file or directory")) {
error = _("Please import the SPI library from the Sketch > Import Library menu.");
msg = _("\nAs of Arduino 0019, the Ethernet library depends on the SPI library." +
"\nYou appear to be using it or another library that depends on the SPI library.\n\n");
}
if (pieces[3].trim().equals("'BYTE' was not declared in this scope")) {
if (error.trim().equals("'BYTE' was not declared in this scope")) {
error = _("The 'BYTE' keyword is no longer supported.");
msg = _("\nAs of Arduino 1.0, the 'BYTE' keyword is no longer supported." +
"\nPlease use Serial.write() instead.\n\n");
}
if (pieces[3].trim().equals("no matching function for call to 'Server::Server(int)'")) {
if (error.trim().equals("no matching function for call to 'Server::Server(int)'")) {
error = _("The Server class has been renamed EthernetServer.");
msg = _("\nAs of Arduino 1.0, the Server class in the Ethernet library " +
"has been renamed to EthernetServer.\n\n");
}
if (pieces[3].trim().equals("no matching function for call to 'Client::Client(byte [4], int)'")) {
if (error.trim().equals("no matching function for call to 'Client::Client(byte [4], int)'")) {
error = _("The Client class has been renamed EthernetClient.");
msg = _("\nAs of Arduino 1.0, the Client class in the Ethernet library " +
"has been renamed to EthernetClient.\n\n");
}
if (pieces[3].trim().equals("'Udp' was not declared in this scope")) {
if (error.trim().equals("'Udp' was not declared in this scope")) {
error = _("The Udp class has been renamed EthernetUdp.");
msg = _("\nAs of Arduino 1.0, the Udp class in the Ethernet library " +
"has been renamed to EthernetUdp.\n\n");
}
if (pieces[3].trim().equals("'class TwoWire' has no member named 'send'")) {
if (error.trim().equals("'class TwoWire' has no member named 'send'")) {
error = _("Wire.send() has been renamed Wire.write().");
msg = _("\nAs of Arduino 1.0, the Wire.send() function was renamed " +
"to Wire.write() for consistency with other libraries.\n\n");
}
if (pieces[3].trim().equals("'class TwoWire' has no member named 'receive'")) {
if (error.trim().equals("'class TwoWire' has no member named 'receive'")) {
error = _("Wire.receive() has been renamed Wire.read().");
msg = _("\nAs of Arduino 1.0, the Wire.receive() function was renamed " +
"to Wire.read() for consistency with other libraries.\n\n");
}
if (pieces[3].trim().equals("'Mouse' was not declared in this scope")) {
if (error.trim().equals("'Mouse' was not declared in this scope")) {
error = _("'Mouse' only supported on the Arduino Leonardo");
//msg = _("\nThe 'Mouse' class is only supported on the Arduino Leonardo.\n\n");
}
if (pieces[3].trim().equals("'Keyboard' was not declared in this scope")) {
if (error.trim().equals("'Keyboard' was not declared in this scope")) {
error = _("'Keyboard' only supported on the Arduino Leonardo");
//msg = _("\nThe 'Keyboard' class is only supported on the Arduino Leonardo.\n\n");
}
@ -799,13 +873,15 @@ public class Compiler implements MessageConsumer {
SketchCode code = sketch.getCode(e.getCodeIndex());
String fileName = (code.isExtension("ino") || code.isExtension("pde")) ? code.getPrettyName() : code.getFileName();
int lineNum = e.getCodeLine() + 1;
s = fileName + ":" + lineNum + ": error: " + pieces[3] + msg;
s = fileName + ":" + lineNum + ": error: " + error + msg;
}
if (e != null) {
if (exception == null || exception.getMessage().equals(e.getMessage())) {
exception = e;
exception.hideStackTrace();
}
}
if (exception == null && e != null) {
exception = e;
exception.hideStackTrace();
}
}
if (s.contains("undefined reference to `SPIClass::begin()'") &&
@ -831,6 +907,8 @@ public class Compiler implements MessageConsumer {
dict.put("source_file", sourceFile.getAbsolutePath());
dict.put("object_file", objectFile.getAbsolutePath());
setupWarningFlags(dict);
String cmd = prefs.getOrExcept(recipe);
try {
return StringReplacer.formatAndSplit(cmd, dict, true);
@ -839,6 +917,19 @@ public class Compiler implements MessageConsumer {
}
}
private void setupWarningFlags(PreferencesMap dict) {
if (dict.containsKey("compiler.warning_level")) {
String key = "compiler.warning_flags." + dict.get("compiler.warning_level");
dict.put("compiler.warning_flags", dict.get(key));
} else {
dict.put("compiler.warning_flags", dict.get("compiler.warning_flags.none"));
}
if (dict.get("compiler.warning_flags") == null) {
dict.remove("compiler.warning_flags");
}
}
/////////////////////////////////////////////////////////////////////////////
private void createFolder(File folder) throws RunnerException {
@ -886,21 +977,21 @@ public class Compiler implements MessageConsumer {
// 2. compile the libraries, outputting .o files to:
// <buildPath>/<library>/
void compileLibraries(List<File> includeFolders) throws RunnerException, PreferencesMapException {
for (Library lib : importedLibraries) {
for (UserLibrary lib : importedLibraries) {
compileLibrary(lib, includeFolders);
}
}
private void compileLibrary(Library lib, List<File> includeFolders)
private void compileLibrary(UserLibrary lib, List<File> includeFolders)
throws RunnerException, PreferencesMapException {
File libFolder = lib.getSrcFolder();
File libBuildFolder = prefs.getFile(("build.path"), lib.getName());
if (lib.useRecursion()) {
// libBuildFolder == {build.path}/LibName
// libFolder == {lib.path}/src
recursiveCompileFilesInFolder(libBuildFolder, libFolder, includeFolders);
} else {
// libFolder == {lib.path}/
// utilityFolder == {lib.path}/utility
@ -908,11 +999,11 @@ public class Compiler implements MessageConsumer {
// utilityBuildFolder == {build.path}/LibName/utility
File utilityFolder = new File(libFolder, "utility");
File utilityBuildFolder = new File(libBuildFolder, "utility");
includeFolders.add(utilityFolder);
compileFilesInFolder(libBuildFolder, libFolder, includeFolders);
compileFilesInFolder(utilityBuildFolder, utilityFolder, includeFolders);
// other libraries should not see this library's utility/ folder
includeFolders.remove(utilityFolder);
}
@ -1031,6 +1122,8 @@ public class Compiler implements MessageConsumer {
dict.put("object_files", objectFileList);
dict.put("ide_version", "" + BaseNoGui.REVISION);
setupWarningFlags(dict);
String[] cmdArray;
String cmd = prefs.getOrExcept("recipe.c.combine.pattern");
try {
@ -1041,6 +1134,18 @@ public class Compiler implements MessageConsumer {
execAsynchronously(cmdArray);
}
void runActions(String recipeClass, PreferencesMap prefs) throws RunnerException, PreferencesMapException {
List<String> patterns = new ArrayList<String>();
for (String key : prefs.keySet()) {
if (key.startsWith("recipe."+recipeClass) && key.endsWith(".pattern"))
patterns.add(key);
}
Collections.sort(patterns);
for (String recipe : patterns) {
runRecipe(recipe);
}
}
void runRecipe(String recipe) throws RunnerException, PreferencesMapException {
PreferencesMap dict = new PreferencesMap(prefs);
dict.put("ide_version", "" + BaseNoGui.REVISION);
@ -1054,6 +1159,32 @@ public class Compiler implements MessageConsumer {
}
execAsynchronously(cmdArray);
}
//7. Save the .hex file
void saveHex() throws RunnerException {
if (!prefs.containsKey("recipe.output.tmp_file") || !prefs.containsKey("recipe.output.save_file")) {
System.err.println(_("Warning: This core does not support exporting sketches. Please consider upgrading it or contacting its author"));
return;
}
PreferencesMap dict = new PreferencesMap(prefs);
dict.put("ide_version", "" + BaseNoGui.REVISION);
try {
String compiledSketch = prefs.getOrExcept("recipe.output.tmp_file");
compiledSketch = StringReplacer.replaceFromMapping(compiledSketch, dict);
String copyOfCompiledSketch = prefs.getOrExcept("recipe.output.save_file");
copyOfCompiledSketch = StringReplacer.replaceFromMapping(copyOfCompiledSketch, dict);
File compiledSketchFile = new File(prefs.get("build.path"), compiledSketch);
File copyOfCompiledSketchFile = new File(sketch.getFolder(), copyOfCompiledSketch);
FileUtils.copyFile(compiledSketchFile, copyOfCompiledSketchFile);
} catch (Exception e) {
throw new RunnerException(e);
}
}
private static String prepareIncludes(List<File> includeFolders) {
String res = "";
@ -1120,12 +1251,12 @@ public class Compiler implements MessageConsumer {
// 2. run preproc on that code using the sugg class name
// to create a single .java file and write to buildpath
FileOutputStream outputStream = null;
try {
// Output file
File streamFile = new File(buildPath, sketch.getName() + ".cpp");
FileOutputStream outputStream = new FileOutputStream(streamFile);
outputStream = new FileOutputStream(streamFile);
preprocessor.write(outputStream);
outputStream.close();
} catch (FileNotFoundException fnfe) {
fnfe.printStackTrace();
String msg = _("Build folder disappeared or could not be written");
@ -1140,15 +1271,32 @@ public class Compiler implements MessageConsumer {
System.err.println(I18n.format(_("Uncaught exception type: {0}"), ex.getClass()));
ex.printStackTrace();
throw new RunnerException(ex.toString());
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
//noop
}
}
}
// grab the imports from the code just preproc'd
importedLibraries = new LibraryList();
importedDuplicateHeaders = new ArrayList<String>();
importedDuplicateLibraries = new ArrayList<LibraryList>();
for (String item : preprocessor.getExtraImports()) {
Library lib = BaseNoGui.importToLibraryTable.get(item);
if (lib != null && !importedLibraries.contains(lib)) {
importedLibraries.add(lib);
LibraryList list = BaseNoGui.importToLibraryTable.get(item);
if (list != null) {
UserLibrary lib = list.peekFirst();
if (lib != null && !importedLibraries.contains(lib)) {
importedLibraries.add(lib);
if (list.size() > 1) {
importedDuplicateHeaders.add(item);
importedDuplicateLibraries.add(list);
}
}
}
}
@ -1180,6 +1328,8 @@ public class Compiler implements MessageConsumer {
* List of library folders.
*/
private LibraryList importedLibraries;
private List<String> importedDuplicateHeaders;
private List<LibraryList> importedDuplicateLibraries;
/**
* Map an error from a set of processed .java files back to its location

View File

@ -0,0 +1,113 @@
/*
TargetPackage - Represents a hardware package
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2014 Cristian Maglie
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
import static processing.app.I18n._;
import static processing.app.I18n.format;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import processing.app.helpers.PreferencesMap;
public class LegacyTargetBoard implements TargetBoard {
private String id;
private PreferencesMap prefs;
private Map<String, PreferencesMap> menuOptions = new LinkedHashMap<String, PreferencesMap>();
private TargetPlatform containerPlatform;
/**
* Create a TargetBoard based on preferences passed as argument.
*
* @param _prefs
* @return
*/
public LegacyTargetBoard(String _id, PreferencesMap _prefs,
TargetPlatform parent) {
containerPlatform = parent;
id = _id;
prefs = new PreferencesMap(_prefs);
// Setup sub-menus
PreferencesMap menus = prefs.firstLevelMap().get("menu");
if (menus != null)
menuOptions = menus.firstLevelMap();
// Auto generate build.board if not set
if (!prefs.containsKey("build.board")) {
String board = containerPlatform.getId() + "_" + id;
board = board.toUpperCase();
prefs.put("build.board", board);
System.out
.println(format(_("Board {0}:{1}:{2} doesn''t define a ''build.board'' preference. Auto-set to: {3}"),
containerPlatform.getContainerPackage().getId(),
containerPlatform.getId(), id, board));
}
}
@Override
public String getName() {
return prefs.get("name");
}
@Override
public String getId() {
return id;
}
@Override
public PreferencesMap getPreferences() {
return prefs;
}
@Override
public boolean hasMenu(String menuId) {
return menuOptions.containsKey(menuId);
}
@Override
public PreferencesMap getMenuLabels(String menuId) {
return menuOptions.get(menuId).topLevelMap();
}
@Override
public String getMenuLabel(String menuId, String selectionId) {
return getMenuLabels(menuId).get(selectionId);
}
@Override
public Set<String> getMenuIds() {
return menuOptions.keySet();
}
@Override
public PreferencesMap getMenuPreferences(String menuId, String selectionId) {
return menuOptions.get(menuId).subTree(selectionId);
}
@Override
public TargetPlatform getContainerPlatform() {
return containerPlatform;
}
}

View File

@ -0,0 +1,89 @@
/*
TargetPackage - Represents a hardware package
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2011 Cristian Maglie
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
import static processing.app.I18n._;
import static processing.app.helpers.filefilters.OnlyDirs.ONLY_DIRS;
import java.io.File;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import processing.app.I18n;
public class LegacyTargetPackage implements TargetPackage {
private String id;
private Map<String, TargetPlatform> platforms;
public LegacyTargetPackage(String _id, File _folder) throws TargetPlatformException {
id = _id;
platforms = new LinkedHashMap<String, TargetPlatform>();
File[] folders = _folder.listFiles(ONLY_DIRS);
if (folders == null)
return;
for (File subFolder : folders) {
if (!subFolder.exists() || !subFolder.canRead())
continue;
String arch = subFolder.getName();
try {
TargetPlatform platform = new LegacyTargetPlatform(arch, subFolder, this);
platforms.put(arch, platform);
} catch (TargetPlatformException e) {
System.out.println(e.getMessage());
}
}
if (platforms.size() == 0) {
throw new TargetPlatformException(I18n
.format(_("No valid hardware definitions found in folder {0}."),
_folder.getName()));
}
}
@Override
public Map<String, TargetPlatform> getPlatforms() {
return platforms;
}
@Override
public Collection<TargetPlatform> platforms() {
return platforms.values();
}
@Override
public TargetPlatform get(String platform) {
return platforms.get(platform);
}
@Override
public boolean hasPlatform(TargetPlatform platform) {
return platforms.containsKey(platform.getId());
}
@Override
public String getId() {
return id;
}
}

View File

@ -0,0 +1,241 @@
/*
TargetPlatform - Represents a hardware platform
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2009-2014 Arduino
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.helpers.PreferencesMap;
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import static processing.app.I18n._;
import static processing.app.I18n.format;
public class LegacyTargetPlatform implements TargetPlatform {
private String id;
private File folder;
private TargetPackage containerPackage;
protected PreferencesMap preferences = new PreferencesMap();
private Map<String, TargetBoard> boards = new LinkedHashMap<String, TargetBoard>();
private TargetBoard defaultBoard;
/**
* Contains preferences for every defined programmer
*/
private Map<String, PreferencesMap> programmers = new LinkedHashMap<String, PreferencesMap>();
/**
* Contains labels for top level menus
*/
private PreferencesMap customMenus = new PreferencesMap();
public LegacyTargetPlatform(String _name, File _folder, TargetPackage parent)
throws TargetPlatformException {
id = _name;
folder = _folder;
containerPackage = parent;
// If there is no boards.txt, this is not a valid 1.5 hardware folder
File boardsFile = new File(folder, "boards.txt");
if (!boardsFile.exists() || !boardsFile.canRead())
throw new TargetPlatformException(
format(_("Could not find boards.txt in {0}. Is it pre-1.5?"),
folder.getAbsolutePath()));
// Load boards
try {
Map<String, PreferencesMap> boardsPreferences = new PreferencesMap(
boardsFile).firstLevelMap();
// Create custom menus for this platform
PreferencesMap menus = boardsPreferences.get("menu");
if (menus != null)
customMenus = menus.topLevelMap();
boardsPreferences.remove("menu");
// Create boards
Set<String> boardIds = boardsPreferences.keySet();
for (String boardId : boardIds) {
PreferencesMap preferences = boardsPreferences.get(boardId);
TargetBoard board = new LegacyTargetBoard(boardId, preferences, this);
boards.put(boardId, board);
// Pick the first board as default
if (defaultBoard == null)
defaultBoard = board;
}
} catch (IOException e) {
throw new TargetPlatformException(format(_("Error loading {0}"),
boardsFile.getAbsolutePath()), e);
}
File platformsFile = new File(folder, "platform.txt");
try {
if (platformsFile.exists() && platformsFile.canRead()) {
preferences.load(platformsFile);
}
} catch (IOException e) {
throw new TargetPlatformException(
format(_("Error loading {0}"), platformsFile.getAbsolutePath()), e);
}
// Allow overriding values in platform.txt. This allows changing
// platform.txt (e.g. to use a system-wide toolchain), without
// having to modify platform.txt (which, when running from git,
// prevents files being marked as changed).
File localPlatformsFile = new File(folder, "platform.local.txt");
try {
if (localPlatformsFile.exists() && localPlatformsFile.canRead()) {
preferences.load(localPlatformsFile);
}
} catch (IOException e) {
throw new TargetPlatformException(
format(_("Error loading {0}"), localPlatformsFile.getAbsolutePath()), e);
}
if (!preferences.containsKey("rewriting") || !"disabled".equals(preferences.get("rewriting"))) {
try {
rewriteKeysOfOldPlatformsTxtAndWarnAboutIt();
} catch (IOException e) {
throw new TargetPlatformException(e);
}
}
File progFile = new File(folder, "programmers.txt");
try {
if (progFile.exists() && progFile.canRead()) {
PreferencesMap prefs = new PreferencesMap();
prefs.load(progFile);
programmers = prefs.firstLevelMap();
}
} catch (IOException e) {
throw new TargetPlatformException(format(_("Error loading {0}"),
progFile.getAbsolutePath()), e);
}
}
private void rewriteKeysOfOldPlatformsTxtAndWarnAboutIt() throws IOException {
File platformRewrite = new File(BaseNoGui.getHardwareFolder(), "platform.keys.rewrite.txt");
PreferencesMap platformRewriteProps = new PreferencesMap(platformRewrite);
PreferencesMap oldProps = platformRewriteProps.subTree("old");
PreferencesMap newProps = platformRewriteProps.subTree("new");
String platformName = preferences.get("name");
if (platformName == null) {
platformName = folder.getAbsolutePath();
}
for (Map.Entry<String, String> entry : oldProps.entrySet()) {
String preferencesKey = entry.getKey().substring(entry.getKey().indexOf(".") + 1);
if (preferences.containsKey(preferencesKey) && entry.getValue().equals(preferences.get(preferencesKey))) {
System.err.println(I18n.format(_("Warning: platform.txt from core '{0}' contains deprecated {1}, automatically converted to {2}. Consider upgrading this core."), platformName, preferencesKey + "=" + entry.getValue(), preferencesKey + "=" + newProps.get(entry.getKey())));
preferences.put(preferencesKey, newProps.get(entry.getKey()));
}
}
PreferencesMap addedProps = platformRewriteProps.subTree("added");
for (Map.Entry<String, String> entry : addedProps.entrySet()) {
String keyToAdd = entry.getKey();
String[] keyToAddParts = keyToAdd.split("\\.");
String keyToAddFirstLevel = keyToAddParts[0];
String keyToAddSecondLevel = keyToAddParts[0] + "." + keyToAddParts[1];
if (!preferences.subTree(keyToAddFirstLevel).isEmpty() && !preferences.subTree(keyToAddSecondLevel).isEmpty() && !preferences.containsKey(keyToAdd)) {
System.err.println(I18n.format(_("Warning: platform.txt from core '{0}' misses property {1}, automatically set to {2}. Consider upgrading this core."), platformName, keyToAdd, entry.getValue()));
preferences.put(keyToAdd, entry.getValue());
}
}
}
@Override
public String getId() {
return id;
}
@Override
public File getFolder() {
return folder;
}
@Override
public Map<String, TargetBoard> getBoards() {
return boards;
}
@Override
public PreferencesMap getCustomMenus() {
return customMenus;
}
@Override
public Set<String> getCustomMenuIds() {
return customMenus.keySet();
}
@Override
public Map<String, PreferencesMap> getProgrammers() {
return programmers;
}
@Override
public PreferencesMap getProgrammer(String programmer) {
return getProgrammers().get(programmer);
}
@Override
public PreferencesMap getTool(String tool) {
return getPreferences().subTree("tools").subTree(tool);
}
@Override
public PreferencesMap getPreferences() {
return preferences;
}
@Override
public TargetBoard getBoard(String boardId) {
if (boards.containsKey(boardId)) {
return boards.get(boardId);
}
return defaultBoard;
}
@Override
public TargetPackage getContainerPackage() {
return containerPackage;
}
@Override
public String toString() {
String res = "TargetPlatform: name=" + id + " boards={\n";
for (String boardId : boards.keySet())
res += " " + boardId + " = " + boards.get(boardId) + "\n";
return res + "}";
}
}

View File

@ -1,76 +1,51 @@
/*
TargetBoard - Represents a hardware board
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2014 Cristian Maglie
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package processing.app.debug;
import static processing.app.I18n._;
import static processing.app.I18n.format;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import processing.app.helpers.PreferencesMap;
public class TargetBoard {
private String id;
private PreferencesMap prefs;
private Map<String, PreferencesMap> menuOptions = new LinkedHashMap<String, PreferencesMap>();
private TargetPlatform containerPlatform;
/**
* Create a TargetBoard based on preferences passed as argument.
*
* @param _prefs
* @return
*/
public TargetBoard(String _id, PreferencesMap _prefs, TargetPlatform parent) {
containerPlatform = parent;
id = _id;
prefs = new PreferencesMap(_prefs);
// Setup sub-menus
PreferencesMap menus = prefs.firstLevelMap().get("menu");
if (menus != null)
menuOptions = menus.firstLevelMap();
// Auto generate build.board if not set
if (!prefs.containsKey("build.board")) {
String board = containerPlatform.getId() + "_" + id;
board = board.toUpperCase();
prefs.put("build.board", board);
System.out
.println(format(
_("Board {0}:{1}:{2} doesn''t define a ''build.board'' preference. Auto-set to: {3}"),
containerPlatform.getContainerPackage().getId(),
containerPlatform.getId(), id, board));
}
}
public interface TargetBoard {
/**
* Get the name of the board.
*
* @return
*/
public String getName() {
return prefs.get("name");
}
public String getName();
/**
* Get the identifier of the board
*
* @return
*/
public String getId() {
return id;
}
public String getId();
/**
* Get the full preferences map of the board with a given identifier
* Get the full preferences map of the board
*
* @return
*/
public PreferencesMap getPreferences() {
return prefs;
}
public PreferencesMap getPreferences();
/**
* Check if the board has a sub menu.
@ -79,9 +54,7 @@ public class TargetBoard {
* The menu ID to check
* @return
*/
public boolean hasMenu(String menuId) {
return menuOptions.containsKey(menuId);
}
public boolean hasMenu(String menuId);
/**
* Returns the options available on a specific menu
@ -90,9 +63,7 @@ public class TargetBoard {
* The menu ID
* @return
*/
public PreferencesMap getMenuLabels(String menuId) {
return menuOptions.get(menuId).topLevelMap();
}
public PreferencesMap getMenuLabels(String menuId);
/**
* Returns the label of the specified option in the specified menu
@ -103,13 +74,9 @@ public class TargetBoard {
* The option ID
* @return
*/
public String getMenuLabel(String menuId, String selectionId) {
return getMenuLabels(menuId).get(selectionId);
}
public String getMenuLabel(String menuId, String selectionId);
public Set<String> getMenuIds() {
return menuOptions.keySet();
}
public Set<String> getMenuIds();
/**
* Returns the configuration parameters to override (as a PreferenceMap) when
@ -121,12 +88,8 @@ public class TargetBoard {
* The option ID
* @return
*/
public PreferencesMap getMenuPreferences(String menuId, String selectionId) {
return menuOptions.get(menuId).subTree(selectionId);
}
public PreferencesMap getMenuPreferences(String menuId, String selectionId);
public TargetPlatform getContainerPlatform() {
return containerPlatform;
}
public TargetPlatform getContainerPlatform();
}

View File

@ -1,9 +1,8 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
TargetPackage - Represents a hardware package
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2011 Cristian Maglie
Copyright (c) 2014 Cristian Maglie
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,61 +20,18 @@
*/
package processing.app.debug;
import static processing.app.I18n._;
import java.io.File;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import processing.app.I18n;
import processing.app.helpers.filefilters.OnlyDirs;
public interface TargetPackage {
public class TargetPackage {
String getId();
private String id;
Map<String, TargetPlatform> getPlatforms();
Map<String, TargetPlatform> platforms = new LinkedHashMap<String, TargetPlatform>();
Collection<TargetPlatform> platforms();
public TargetPackage(String _id, File _folder) throws TargetPlatformException {
id = _id;
TargetPlatform get(String platform);
File[] folders = _folder.listFiles(new OnlyDirs());
if (folders == null)
return;
for (File subFolder : folders) {
if (!subFolder.exists() || !subFolder.canRead())
continue;
String arch = subFolder.getName();
try {
TargetPlatform platform = new TargetPlatform(arch, subFolder, this);
platforms.put(arch, platform);
} catch (TargetPlatformException e) {
System.out.println(e.getMessage());
}
}
if (platforms.size() == 0) {
throw new TargetPlatformException(I18n
.format(_("No valid hardware definitions found in folder {0}."),
_folder.getName()));
}
}
public Map<String, TargetPlatform> getPlatforms() {
return platforms;
}
public Collection<TargetPlatform> platforms() {
return platforms.values();
}
public TargetPlatform get(String platform) {
return platforms.get(platform);
}
public String getId() {
return id;
}
boolean hasPlatform(TargetPlatform platform);
}

View File

@ -1,9 +1,8 @@
/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
TargetPlatform - Represents a hardware platform
Part of the Arduino project - http://www.arduino.cc/
Copyright (c) 2009 David A. Mellis
Copyright (c) 2014 Arduino
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,174 +20,78 @@
*/
package processing.app.debug;
import static processing.app.I18n._;
import static processing.app.I18n.format;
import java.io.File;
import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import processing.app.helpers.PreferencesMap;
public class TargetPlatform {
public interface TargetPlatform {
private String id;
private File folder;
private TargetPackage containerPackage;
public String getId();
public File getFolder();
/**
* Contains preferences for every defined board
* Get TargetBoards under this TargetPlatform into a Map that maps the board
* id with the corresponding TargetBoard
*
* @return a Map<String, TargetBoard>
*/
private Map<String, TargetBoard> boards = new LinkedHashMap<String, TargetBoard>();
private TargetBoard defaultBoard;
public Map<String, TargetBoard> getBoards();
public PreferencesMap getCustomMenus();
/**
* Contains preferences for every defined programmer
* Return ids for top level menus
*
* @return a Set<String> with the ids of the top level custom menus
*/
private Map<String, PreferencesMap> programmers = new LinkedHashMap<String, PreferencesMap>();
public Set<String> getCustomMenuIds();
/**
* Contains preferences for platform
* Get preferences for all programmers
*
* @return
*/
private PreferencesMap preferences = new PreferencesMap();
public Map<String, PreferencesMap> getProgrammers();
/**
* Contains labels for top level menus
* Get preferences for a specific programmer
*
* @param programmer
* @return
*/
private PreferencesMap customMenus = new PreferencesMap();
public PreferencesMap getProgrammer(String programmer);
public TargetPlatform(String _name, File _folder, TargetPackage parent)
throws TargetPlatformException {
/**
* Get preferences for a specific tool
*
* @param tool
* @return
*/
public PreferencesMap getTool(String tool);
id = _name;
folder = _folder;
containerPackage = parent;
/**
* Return TargetPlatform preferences
*
* @return
*/
public PreferencesMap getPreferences();
// If there is no boards.txt, this is not a valid 1.5 hardware folder
File boardsFile = new File(folder, "boards.txt");
if (!boardsFile.exists() || !boardsFile.canRead())
throw new TargetPlatformException(
format(_("Could not find boards.txt in {0}. Is it pre-1.5?"),
folder.getAbsolutePath()));
/**
* Get a target board
*
* @param boardId
* @return
*/
public TargetBoard getBoard(String boardId);
// Load boards
try {
Map<String, PreferencesMap> boardsPreferences = new PreferencesMap(
boardsFile).firstLevelMap();
/**
* Get the TargetPackage that contains this TargetPlatform
*
* @return
*/
public TargetPackage getContainerPackage();
// Create custom menus for this platform
PreferencesMap menus = boardsPreferences.get("menu");
if (menus != null)
customMenus = menus.topLevelMap();
boardsPreferences.remove("menu");
// Create boards
Set<String> boardIds = boardsPreferences.keySet();
for (String boardId : boardIds) {
PreferencesMap preferences = boardsPreferences.get(boardId);
TargetBoard board = new TargetBoard(boardId, preferences, this);
boards.put(boardId, board);
// Pick the first board as default
if (defaultBoard == null)
defaultBoard = board;
}
} catch (IOException e) {
throw new TargetPlatformException(format(_("Error loading {0}"),
boardsFile.getAbsolutePath()), e);
}
File platformsFile = new File(folder, "platform.txt");
try {
if (platformsFile.exists() && platformsFile.canRead()) {
preferences.load(platformsFile);
}
} catch (IOException e) {
throw new TargetPlatformException(
format(_("Error loading {0}"), platformsFile.getAbsolutePath()), e);
}
// Allow overriding values in platform.txt. This allows changing
// platform.txt (e.g. to use a system-wide toolchain), without
// having to modify platform.txt (which, when running from git,
// prevents files being marked as changed).
File localPlatformsFile = new File(folder, "platform.local.txt");
try {
if (localPlatformsFile.exists() && localPlatformsFile.canRead()) {
preferences.load(localPlatformsFile);
}
} catch (IOException e) {
throw new TargetPlatformException(
format(_("Error loading {0}"), localPlatformsFile.getAbsolutePath()), e);
}
File progFile = new File(folder, "programmers.txt");
try {
if (progFile.exists() && progFile.canRead()) {
PreferencesMap prefs = new PreferencesMap();
prefs.load(progFile);
programmers = prefs.firstLevelMap();
}
} catch (IOException e) {
throw new TargetPlatformException(format(_("Error loading {0}"), progFile
.getAbsolutePath()), e);
}
}
public String getId() {
return id;
}
public File getFolder() {
return folder;
}
public Map<String, TargetBoard> getBoards() {
return boards;
}
public PreferencesMap getCustomMenus() {
return customMenus;
}
public Set<String> getCustomMenuIds() {
return customMenus.keySet();
}
public Map<String, PreferencesMap> getProgrammers() {
return programmers;
}
public PreferencesMap getProgrammer(String programmer) {
return getProgrammers().get(programmer);
}
public PreferencesMap getTool(String tool) {
return getPreferences().subTree("tools").subTree(tool);
}
public PreferencesMap getPreferences() {
return preferences;
}
public TargetBoard getBoard(String boardId) {
if (boards.containsKey(boardId)) {
return boards.get(boardId);
}
return defaultBoard;
}
public TargetPackage getContainerPackage() {
return containerPackage;
}
@Override
public String toString() {
String res = "TargetPlatform: name=" + id + " boards={\n";
for (String boardId : boards.keySet())
res += " " + boardId + " = " + boards.get(boardId) + "\n";
return res + "}";
}
}

View File

@ -1,13 +1,5 @@
package processing.app.helpers;
import static processing.app.I18n._;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import processing.app.BaseNoGui;
import processing.app.I18n;
import processing.app.PreferencesData;
@ -16,34 +8,59 @@ import processing.app.debug.TargetPackage;
import processing.app.debug.TargetPlatform;
import processing.app.legacy.PApplet;
import java.io.File;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import static processing.app.I18n._;
public class CommandlineParser {
protected static enum ACTION { GUI, NOOP, VERIFY, UPLOAD, GET_PREF };
private enum ACTION {
GUI, NOOP, VERIFY("--verify"), UPLOAD("--upload"), GET_PREF("--get-pref"), INSTALL_BOARD("--install-boards"), INSTALL_LIBRARY("--install-library");
private final String value;
ACTION() {
this.value = null;
}
ACTION(String value) {
this.value = value;
}
}
private ACTION action = ACTION.GUI;
private boolean doVerboseBuild = false;
private boolean doVerboseUpload = false;
private boolean doUseProgrammer = false;
private boolean preserveTempFiles;
private boolean noUploadPort = false;
private boolean forceSavePrefs = false;
private String getPref = null;
private String getPref;
private String boardToInstall;
private String libraryToInstall;
private List<String> filenames = new LinkedList<String>();
public static CommandlineParser newCommandlineParser(String[] args) {
return new CommandlineParser(args);
}
private CommandlineParser(String[] args) {
parseArguments(args);
checkAction();
}
private void parseArguments(String[] args) {
// Map of possible actions and corresponding options
final Map<String, ACTION> actions = new HashMap<String, ACTION>();
actions.put("--verify", ACTION.VERIFY);
actions.put("--upload", ACTION.UPLOAD);
actions.put("--get-pref", ACTION.GET_PREF);
actions.put("--install-boards", ACTION.INSTALL_BOARD);
actions.put("--install-library", ACTION.INSTALL_LIBRARY);
// Check if any files were passed in on the command line
for (int i = 0; i < args.length; i++) {
@ -56,10 +73,25 @@ public class CommandlineParser {
}
if (a == ACTION.GET_PREF) {
i++;
if (i >= args.length)
BaseNoGui.showError(null, _("Argument required for --get-pref"), 3);
if (i >= args.length) {
BaseNoGui.showError(null, I18n.format(_("Argument required for {0}"), a.value), 3);
}
getPref = args[i];
}
if (a == ACTION.INSTALL_BOARD) {
i++;
if (i >= args.length) {
BaseNoGui.showError(null, I18n.format(_("Argument required for {0}"), a.value), 3);
}
boardToInstall = args[i];
}
if (a == ACTION.INSTALL_LIBRARY) {
i++;
if (i >= args.length) {
BaseNoGui.showError(null, I18n.format(_("Argument required for {0}"), a.value), 3);
}
libraryToInstall = args[i];
}
action = a;
continue;
}
@ -74,6 +106,12 @@ public class CommandlineParser {
action = ACTION.NOOP;
continue;
}
if (args[i].equals("--preserve-temp-files")) {
preserveTempFiles = true;
if (action == ACTION.GUI)
action = ACTION.NOOP;
continue;
}
if (args[i].equals("--verbose-build")) {
doVerboseBuild = true;
if (action == ACTION.GUI)
@ -164,7 +202,7 @@ public class CommandlineParser {
filenames.add(args[i]);
}
}
private void checkAction() {
if ((action == ACTION.UPLOAD || action == ACTION.VERIFY) && filenames.size() != 1)
BaseNoGui.showError(null, _("Must specify exactly one sketch file"), 3);
@ -179,7 +217,7 @@ public class CommandlineParser {
private void processBoardArgument(String selectBoard) {
// No board selected? Nothing to do
if (selectBoard == null)
return;
return;
String[] split = selectBoard.split(":", 4);
@ -251,27 +289,27 @@ public class CommandlineParser {
public List<String> getFilenames() {
return filenames;
}
public boolean isGetPrefMode() {
return action == ACTION.GET_PREF;
}
public boolean isGuiMode() {
return action == ACTION.GUI;
}
public boolean isNoOpMode() {
return action == ACTION.NOOP;
}
public boolean isUploadMode() {
return action == ACTION.UPLOAD;
}
public boolean isVerifyMode() {
return action == ACTION.VERIFY;
}
public boolean isVerifyOrUploadMode() {
return isVerifyMode() || isUploadMode();
}
@ -284,4 +322,23 @@ public class CommandlineParser {
return noUploadPort;
}
public boolean isInstallBoard() {
return action == ACTION.INSTALL_BOARD;
}
public boolean isInstallLibrary() {
return action == ACTION.INSTALL_LIBRARY;
}
public String getBoardToInstall() {
return this.boardToInstall;
}
public String getLibraryToInstall() {
return libraryToInstall;
}
public boolean isPreserveTempFiles() {
return preserveTempFiles;
}
}

View File

@ -73,17 +73,28 @@ public class FileUtils {
}
public static void recursiveDelete(File file) {
if (file == null)
if (file == null) {
return;
}
if (file.isDirectory()) {
for (File current : file.listFiles())
File[] files = file.listFiles();
if (files == null) {
return;
}
for (File current : files) {
recursiveDelete(current);
}
}
file.delete();
}
public static File createTempFolder() throws IOException {
File tmpFolder = new File(System.getProperty("java.io.tmpdir"), "arduino_" + new Random().nextInt(1000000));
return createTempFolderIn(new File(System.getProperty("java.io.tmpdir")));
}
public static File createTempFolderIn(File parent) throws IOException {
File tmpFolder = new File(parent, "arduino_"
+ new Random().nextInt(1000000));
if (!tmpFolder.mkdir()) {
throw new IOException("Unable to create temp folder " + tmpFolder);
}
@ -249,5 +260,21 @@ public class FileUtils {
return result;
}
public static File newFile(File parent, String... parts) {
File result = parent;
for (String part : parts) {
result = new File(result, part);
}
return result;
}
public static boolean deleteIfExists(File file) {
if (file == null) {
return true;
}
return file.delete();
}
}

View File

@ -11,7 +11,7 @@ public abstract class NetUtils {
private static boolean isReachableByEcho(InetAddress address) {
try {
return address.isReachable(100);
return address.isReachable(300);
} catch (IOException e) {
return false;
}
@ -38,7 +38,7 @@ public abstract class NetUtils {
Socket socket = null;
try {
socket = new Socket();
socket.connect(new InetSocketAddress(address, port), 300);
socket.connect(new InetSocketAddress(address, port), 1000);
return true;
} catch (IOException e) {
return false;

View File

@ -21,18 +21,14 @@
*/
package processing.app.helpers;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import processing.app.legacy.PApplet;
import java.io.*;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import processing.app.legacy.PApplet;
@SuppressWarnings("serial")
public class PreferencesMap extends LinkedHashMap<String, String> {
@ -71,7 +67,15 @@ public class PreferencesMap extends LinkedHashMap<String, String> {
* @throws IOException
*/
public void load(File file) throws IOException {
load(new FileInputStream(file));
FileInputStream fileInputStream = null;
try {
fileInputStream = new FileInputStream(file);
load(fileInputStream);
} finally {
if (fileInputStream != null) {
fileInputStream.close();
}
}
}
protected String processPlatformSuffix(String key, String suffix, boolean isCurrentPlatform) {
@ -311,7 +315,7 @@ public class PreferencesMap extends LinkedHashMap<String, String> {
* insensitive compared), <b>false</b> in any other case
*/
public boolean getBoolean(String key) {
return new Boolean(get(key));
return Boolean.valueOf(get(key));
}
/**

View File

@ -26,4 +26,18 @@ public class StringUtils {
String regex = pattern.replace("?", ".?").replace("*", ".*?");
return input.matches(regex);
}
/**
* Returns the string without trailing whitespace characters
*
* @param s
* @return
*/
public static String rtrim(String s) {
int i = s.length() - 1;
while (i >= 0 && Character.isWhitespace(s.charAt(i))) {
i--;
}
return s.substring(0, i + 1);
}
}

View File

@ -32,11 +32,17 @@ import java.io.FilenameFilter;
*/
public class OnlyDirs implements FilenameFilter {
public boolean accept(File dir, String name) {
if (name.charAt(0) == '.')
return false;
if (name.equals("CVS"))
return false;
return new File(dir, name).isDirectory();
}
public boolean accept(File dir, String name) {
if (name.charAt(0) == '.')
return false;
if (name.equals("CVS"))
return false;
return new File(dir, name).isDirectory();
}
/**
* An handy pre-instantiated object
*/
public static final OnlyDirs ONLY_DIRS = new OnlyDirs();
}

View File

@ -29,13 +29,15 @@ public class OnlyFilesWithExtension implements FilenameFilter {
String extensions[];
public OnlyFilesWithExtension(String... ext) {
extensions = ext;
this.extensions = ext;
}
public boolean accept(File dir, String name) {
for (String ext : extensions)
if (name.endsWith(ext))
for (String ext : extensions) {
if (name.endsWith(ext)) {
return true;
}
}
return false;
}

View File

@ -1,16 +1,6 @@
package processing.app.legacy;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.io.*;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.StringTokenizer;
@ -276,15 +266,26 @@ public class PApplet {
}
static public String[] loadStrings(File file) {
InputStream is = createInput(file);
if (is != null) return loadStrings(is);
return null;
InputStream is = null;
try {
is = createInput(file);
if (is != null) return loadStrings(is);
return null;
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
// noop
}
}
}
}
static public String[] loadStrings(InputStream input) {
BufferedReader reader = null;
try {
BufferedReader reader =
new BufferedReader(new InputStreamReader(input, "UTF-8"));
reader = new BufferedReader(new InputStreamReader(input, "UTF-8"));
String lines[] = new String[100];
int lineCount = 0;
@ -297,7 +298,6 @@ public class PApplet {
}
lines[lineCount++] = line;
}
reader.close();
if (lineCount == lines.length) {
return lines;
@ -311,6 +311,15 @@ public class PApplet {
} catch (IOException e) {
e.printStackTrace();
//throw new RuntimeException("Error inside loadStrings()");
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
//ignore
}
}
}
return null;
}
@ -321,14 +330,29 @@ public class PApplet {
static public void saveStrings(File file, String strings[]) {
saveStrings(createOutput(file), strings);
OutputStream outputStream = null;
try {
outputStream = createOutput(file);
saveStrings(outputStream, strings);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
//noop
}
}
}
}
static public void saveStrings(OutputStream output, String strings[]) {
PrintWriter writer = createWriter(output);
for (int i = 0; i < strings.length; i++) {
writer.println(strings[i]);
if (writer == null) {
return;
}
for (String string : strings) {
writer.println(string);
}
writer.flush();
writer.close();

View File

@ -0,0 +1,151 @@
/*
* This file is part of Arduino.
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*
* Copyright 2015 Arduino LLC (http://www.arduino.cc/)
*/
package processing.app.linux;
import javax.swing.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class GTKLookAndFeelFixer {
/*
* All functions of this class courtesy of Klaus Reimer
* https://www.ailis.de/~k/archives/67-Workaround-for-borderless-Java-Swing-menus-on-Linux.html
*/
/*
* This is free and unencumbered software released into the public domain.
*
* Anyone is free to copy, modify, publish, use, compile, sell, or
* distribute this software, either in source code form or as a compiled
* binary, for any purpose, commercial or non-commercial, and by any
* means.
*
* In jurisdictions that recognize copyright laws, the author or authors
* of this software dedicate any and all copyright interest in the
* software to the public domain. We make this dedication for the benefit
* of the public at large and to the detriment of our heirs and
* successors. We intend this dedication to be an overt act of
* relinquishment in perpetuity of all present and future rights to this
* software under copyright law.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* For more information, please refer to <http://unlicense.org/>
*/
/**
* Swing menus are looking pretty bad on Linux when the GTK LaF is used (See
* bug #6925412). It will most likely never be fixed anytime soon so this
* method provides a workaround for it. It uses reflection to change the GTK
* style objects of Swing so popup menu borders have a minimum thickness of
* 1 and menu separators have a minimum vertical thickness of 1.
*/
public static void installGtkPopupBugWorkaround() {
// Get current look-and-feel implementation class
LookAndFeel laf = UIManager.getLookAndFeel();
Class<?> lafClass = laf.getClass();
// Do nothing when not using the problematic LaF
if (!lafClass.getName().equals("com.sun.java.swing.plaf.gtk.GTKLookAndFeel")) {
return;
}
// We do reflection from here on. Failure is silently ignored. The
// workaround is simply not installed when something goes wrong here
try {
// Access the GTK style factory
Field field = lafClass.getDeclaredField("styleFactory");
boolean accessible = field.isAccessible();
field.setAccessible(true);
Object styleFactory = field.get(laf);
field.setAccessible(accessible);
// Fix the horizontal and vertical thickness of popup menu style
Object style = getGtkStyle(styleFactory, new JPopupMenu(), "POPUP_MENU");
fixGtkThickness(style, "yThickness");
fixGtkThickness(style, "xThickness");
// Fix the vertical thickness of the popup menu separator style
style = getGtkStyle(styleFactory, new JSeparator(), "POPUP_MENU_SEPARATOR");
fixGtkThickness(style, "yThickness");
} catch (Exception e) {
// Silently ignored. Workaround can't be applied.
}
}
/**
* Called internally by installGtkPopupBugWorkaround to fix the thickness
* of a GTK style field by setting it to a minimum value of 1.
*
* @param style The GTK style object.
* @param fieldName The field name.
* @throws Exception When reflection fails.
*/
private static void fixGtkThickness(Object style, String fieldName) throws Exception {
Field field = style.getClass().getDeclaredField(fieldName);
boolean accessible = field.isAccessible();
field.setAccessible(true);
field.setInt(style, Math.max(1, field.getInt(style)));
field.setAccessible(accessible);
}
/**
* Called internally by installGtkPopupBugWorkaround. Returns a specific
* GTK style object.
*
* @param styleFactory The GTK style factory.
* @param component The target component of the style.
* @param regionName The name of the target region of the style.
* @return The GTK style.
* @throws Exception When reflection fails.
*/
private static Object getGtkStyle(Object styleFactory, JComponent component, String regionName) throws Exception {
// Create the region object
Class<?> regionClass = Class.forName("javax.swing.plaf.synth.Region");
Field field = regionClass.getField(regionName);
Object region = field.get(regionClass);
// Get and return the style
Class<?> styleFactoryClass = styleFactory.getClass();
Method method = styleFactoryClass.getMethod("getStyle", JComponent.class, regionClass);
boolean accessible = method.isAccessible();
method.setAccessible(true);
Object style = method.invoke(styleFactory, component, region);
method.setAccessible(accessible);
return style;
}
}

View File

@ -26,10 +26,12 @@ import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.Executor;
import processing.app.PreferencesData;
import processing.app.debug.TargetPackage;
import processing.app.tools.ExternalProcessExecutor;
import processing.app.legacy.PConstants;
import processing.app.tools.CollectStdOutExecutor;
import java.io.*;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Map;
@ -42,17 +44,7 @@ public class Platform extends processing.app.Platform {
// TODO Need to be smarter here since KDE people ain't gonna like that GTK.
// It may even throw a weird exception at 'em for their trouble.
public void setLookAndFeel() throws Exception {
// Linux is by default even uglier than metal (Motif?).
// Actually, i'm using native menus, so they're even uglier
// and Motif-looking (Lesstif?). Ick. Need to fix this.
//String lfname = UIManager.getCrossPlatformLookAndFeelClassName();
//UIManager.setLookAndFeel(lfname);
// For 0120, trying out the gtk+ look and feel as the default.
// This is available in Java 1.4.2 and later, and it can't possibly
// be any worse than Metal. (Ocean might also work, but that's for
// Java 1.5, and we aren't going there yet)
//UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
GTKLookAndFeelFixer.installGtkPopupBugWorkaround();
}
@ -130,8 +122,9 @@ public class Platform extends processing.app.Platform {
@Override
public Map<String, Object> resolveDeviceAttachedTo(String serial, Map<String, TargetPackage> packages, String devicesListOutput) {
assert packages != null;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Executor executor = new ExternalProcessExecutor(baos);
Executor executor = new CollectStdOutExecutor(baos);
try {
CommandLine toDevicePath = CommandLine.parse("udevadm info -q path -n " + serial);

View File

@ -26,12 +26,12 @@ import cc.arduino.packages.BoardPort;
import com.apple.eio.FileManager;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.Executor;
import org.apache.commons.lang3.StringUtils;
import processing.app.debug.TargetPackage;
import processing.app.tools.ExternalProcessExecutor;
import processing.app.legacy.PApplet;
import processing.app.legacy.PConstants;
import processing.app.tools.CollectStdOutExecutor;
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.lang.reflect.Method;
@ -45,12 +45,9 @@ import java.util.List;
*/
public class Platform extends processing.app.Platform {
private String osArch;
public void setLookAndFeel() throws Exception {
// Use the Quaqua L & F on OS X to make JFileChooser less awful
UIManager.setLookAndFeel("ch.randelshofer.quaqua.QuaquaLookAndFeel");
// undo quaqua trying to fix the margins, since we've already
// hacked that in, bit by bit, over the years
UIManager.put("Component.visualMargin", new Insets(1, 1, 1, 1));
}
public Platform() {
@ -59,35 +56,18 @@ public class Platform extends processing.app.Platform {
Toolkit.getDefaultToolkit();
}
public void init() {
public void init() throws IOException {
System.setProperty("apple.laf.useScreenMenuBar", "true");
/*
try {
String name = "processing.app.macosx.ThinkDifferent";
Class osxAdapter = ClassLoader.getSystemClassLoader().loadClass(name);
Class[] defArgs = { Base.class };
Method registerMethod = osxAdapter.getDeclaredMethod("register", defArgs);
if (registerMethod != null) {
Object[] args = { this };
registerMethod.invoke(osxAdapter, args);
}
} catch (NoClassDefFoundError e) {
// This will be thrown first if the OSXAdapter is loaded on a system without the EAWT
// because OSXAdapter extends ApplicationAdapter in its def
System.err.println("This version of Mac OS X does not support the Apple EAWT." +
"Application Menu handling has been disabled (" + e + ")");
discoverRealOsArch();
}
} catch (ClassNotFoundException e) {
// This shouldn't be reached; if there's a problem with the OSXAdapter
// we should get the above NoClassDefFoundError first.
System.err.println("This version of Mac OS X does not support the Apple EAWT. " +
"Application Menu handling has been disabled (" + e + ")");
} catch (Exception e) {
System.err.println("Exception while loading BaseOSX:");
e.printStackTrace();
}
*/
private void discoverRealOsArch() throws IOException {
CommandLine uname = CommandLine.parse("uname -m");
ByteArrayOutputStream baos = new ByteArrayOutputStream();
CollectStdOutExecutor executor = new CollectStdOutExecutor(baos);
executor.execute(uname);
osArch = StringUtils.trim(new String(baos.toByteArray()));
}
@ -115,7 +95,7 @@ public class Platform extends processing.app.Platform {
public void openURL(String url) throws Exception {
if (PApplet.javaVersion < 1.6f) {
if (url.startsWith("http://")) {
if (url.startsWith("http")) {
// formerly com.apple.eio.FileManager.openURL(url);
// but due to deprecation, instead loading dynamically
try {
@ -139,7 +119,7 @@ public class Platform extends processing.app.Platform {
// for Java 1.6, replacing with java.awt.Desktop.browse()
// and java.awt.Desktop.open()
if (url.startsWith("http://")) { // browse to a location
if (url.startsWith("http")) { // browse to a location
Method browseMethod =
desktopClass.getMethod("browse", new Class[] { URI.class });
browseMethod.invoke(desktop, new Object[] { new URI(url) });
@ -211,6 +191,7 @@ public class Platform extends processing.app.Platform {
@Override
public Map<String, Object> resolveDeviceAttachedTo(String serial, Map<String, TargetPackage> packages, String devicesListOutput) {
assert packages != null;
if (devicesListOutput == null) {
return super.resolveDeviceAttachedTo(serial, packages, devicesListOutput);
}
@ -231,7 +212,7 @@ public class Platform extends processing.app.Platform {
@Override
public String preListAllCandidateDevices() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Executor executor = new ExternalProcessExecutor(baos);
Executor executor = new CollectStdOutExecutor(baos);
try {
CommandLine toDevicePath = CommandLine.parse("/usr/sbin/system_profiler SPUSBDataType");
@ -250,11 +231,16 @@ public class Platform extends processing.app.Platform {
List<BoardPort> filteredPorts = new LinkedList<BoardPort>();
for (BoardPort port : ports) {
if (!port.getAddress().startsWith("/dev/cu.")) {
if (!port.getAddress().startsWith("/dev/tty.")) {
filteredPorts.add(port);
}
}
return filteredPorts;
}
@Override
public String getOsArch() {
return osArch;
}
}

View File

@ -0,0 +1,126 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.packages;
import java.io.File;
import java.util.Arrays;
import java.util.List;
import cc.arduino.contributions.libraries.ContributedLibraryReference;
public class LegacyUserLibrary extends UserLibrary {
private String name;
public static LegacyUserLibrary create(File libFolder) {
// construct an old style library
LegacyUserLibrary res = new LegacyUserLibrary();
res.setInstalledFolder(libFolder);
res.setInstalled(true);
res.layout = LibraryLayout.FLAT;
res.name = libFolder.getName();
return res;
}
@Override
public String getName() {
return name;
}
@Override
public List<String> getArchitectures() {
return Arrays.asList("*");
}
@Override
public String getAuthor() {
return null;
}
@Override
public String getParagraph() {
return null;
}
@Override
public String getSentence() {
return null;
}
@Override
public String getWebsite() {
return null;
}
@Override
public String getCategory() {
return "Uncategorized";
}
@Override
public String getLicense() {
return null;
}
@Override
public String getVersion() {
return null;
}
@Override
public String getMaintainer() {
return null;
}
@Override
public String getChecksum() {
return null;
}
@Override
public long getSize() {
return 0;
}
@Override
public String getUrl() {
return null;
}
@Override
public List<ContributedLibraryReference> getRequires() {
return null;
}
@Override
public String toString() {
return "LegacyLibrary:" + name + "\n";
}
}

View File

@ -1,14 +1,42 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.packages;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import processing.app.helpers.FileUtils;
@SuppressWarnings("serial")
public class LibraryList extends ArrayList<Library> {
public class LibraryList extends LinkedList<UserLibrary> {
public LibraryList(LibraryList libs) {
super(libs);
@ -18,53 +46,46 @@ public class LibraryList extends ArrayList<Library> {
super();
}
public Library getByName(String name) {
for (Library l : this)
public LibraryList(List<UserLibrary> ideLibs) {
super(ideLibs);
}
public UserLibrary getByName(String name) {
for (UserLibrary l : this)
if (l.getName().equals(name))
return l;
return null;
}
public void addOrReplace(Library lib) {
Library l = getByName(lib.getName());
if (l != null)
remove(l);
public void addOrReplace(UserLibrary lib) {
remove(lib);
add(lib);
}
public void addOrReplaceAll(Collection<? extends Library> c) {
for (Library l : c)
addOrReplace(l);
public void remove(UserLibrary lib) {
UserLibrary l = getByName(lib.getName());
if (l != null)
super.remove(l);
}
public void sort() {
Collections.sort(this, Library.CASE_INSENSITIVE_ORDER);
}
public Library search(String name, String arch) {
for (Library lib : this) {
if (!lib.getName().equals(name))
continue;
if (!lib.supportsArchitecture(arch))
continue;
return lib;
}
return null;
}
public LibraryList filterByArchitecture(String reqArch) {
LibraryList res = new LibraryList();
for (Library lib : this)
if (lib.supportsArchitecture(reqArch))
res.add(lib);
return res;
Collections.sort(this, UserLibrary.CASE_INSENSITIVE_ORDER);
}
public LibraryList filterLibrariesInSubfolder(File subFolder) {
LibraryList res = new LibraryList();
for (Library lib : this)
if (FileUtils.isSubDirectory(subFolder, lib.getFolder()))
for (UserLibrary lib : this) {
if (FileUtils.isSubDirectory(subFolder, lib.getInstalledFolder())) {
res.add(lib);
}
}
return res;
}
public boolean hasLibrary(UserLibrary lib) {
for (UserLibrary l : this)
if (l == lib) return true;
return false;
}
}

View File

@ -1,16 +1,46 @@
/*
* This file is part of Arduino.
*
* Copyright 2014 Arduino LLC (http://www.arduino.cc/)
*
* Arduino is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
* As a special exception, you may use this file as part of a free software
* library without restriction. Specifically, if other files instantiate
* templates or use macros or inline functions from this file, or you compile
* this file and link it with other files to produce an executable, this
* file does not by itself cause the resulting executable to be covered by
* the GNU General Public License. This exception does not however
* invalidate any other reasons why the executable file might be covered by
* the GNU General Public License.
*/
package processing.app.packages;
import cc.arduino.contributions.libraries.ContributedLibrary;
import cc.arduino.contributions.libraries.ContributedLibraryReference;
import processing.app.helpers.FileUtils;
import processing.app.helpers.PreferencesMap;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import processing.app.helpers.FileUtils;
import processing.app.helpers.PreferencesMap;
public class Library {
public class UserLibrary extends ContributedLibrary {
private String name;
private String version;
@ -18,44 +48,23 @@ public class Library {
private String maintainer;
private String sentence;
private String paragraph;
private String url;
private String website;
private String category;
private String license;
private List<String> architectures;
private File folder;
private boolean isLegacy;
private enum LibraryLayout { FLAT, RECURSIVE };
private LibraryLayout layout;
private List<String> types;
private List<String> declaredTypes;
private static final List<String> MANDATORY_PROPERTIES = Arrays
.asList(new String[] { "name", "version", "author", "maintainer",
"sentence", "paragraph", "url" });
.asList(new String[]{"name", "version", "author", "maintainer",
"sentence", "paragraph", "url"});
private static final List<String> CATEGORIES = Arrays.asList(new String[] {
"Display", "Communication", "Signal Input/Output", "Sensors",
"Device Control", "Timing", "Data Storage", "Data Processing", "Other",
"Uncategorized" });
private static final List<String> CATEGORIES = Arrays.asList(new String[]{
"Display", "Communication", "Signal Input/Output", "Sensors",
"Device Control", "Timing", "Data Storage", "Data Processing", "Other",
"Uncategorized"});
/**
* Scans inside a folder and create a Library object out of it. Automatically
* detects legacy libraries. Automatically fills metadata from
* library.properties file if found.
*
* @param libFolder
* @return
*/
static public Library create(File libFolder) throws IOException {
// A library is considered "new" if it contains a file called
// "library.properties"
File check = new File(libFolder, "library.properties");
if (!check.exists() || !check.isFile())
return createLegacyLibrary(libFolder);
else
return createLibrary(libFolder);
}
private static Library createLibrary(File libFolder) throws IOException {
public static UserLibrary create(File libFolder) throws IOException {
// Parse metadata
File propertiesFile = new File(libFolder, "library.properties");
PreferencesMap properties = new PreferencesMap();
@ -66,16 +75,16 @@ public class Library {
// Compatibility with 1.5 rev.1 libraries:
// "email" field changed to "maintainer"
if (!properties.containsKey("maintainer") &&
properties.containsKey("email"))
if (!properties.containsKey("maintainer") && properties.containsKey("email")) {
properties.put("maintainer", properties.get("email"));
}
// Compatibility with 1.5 rev.1 libraries:
// "arch" folder no longer supported
File archFolder = new File(libFolder, "arch");
if (archFolder.isDirectory())
throw new IOException("'arch' folder is no longer supported! See "
+ "http://goo.gl/gfFJzU for more information");
+ "http://goo.gl/gfFJzU for more information");
// Check mandatory properties
for (String p : MANDATORY_PROPERTIES)
@ -93,7 +102,7 @@ public class Library {
File utilFolder = new File(libFolder, "utility");
if (utilFolder.exists() && utilFolder.isDirectory()) {
throw new IOException(
"Library can't use both 'src' and 'utility' folders.");
"Library can't use both 'src' and 'utility' folders.");
}
} else {
// Layout with source code on library's root and "utility" folders
@ -104,8 +113,7 @@ public class Library {
for (File file : libFolder.listFiles()) {
if (file.isDirectory()) {
if (FileUtils.isSCCSOrHiddenFile(file)) {
System.out.println("WARNING: Spurious " + file.getName() +
" folder in '" + properties.get("name") + "' library");
System.out.println("WARNING: Spurious " + file.getName() + " folder in '" + properties.get("name") + "' library");
continue;
}
}
@ -123,110 +131,88 @@ public class Library {
if (category == null)
category = "Uncategorized";
if (!CATEGORIES.contains(category)) {
category = "Uncategorized";
System.out.println("WARNING: Category '" + category + "' in library " +
properties.get("name") + " is not valid. Setting to 'Uncategorized'");
properties.get("name") + " is not valid. Setting to 'Uncategorized'");
category = "Uncategorized";
}
String license = properties.get("license");
if (license == null)
if (license == null) {
license = "Unspecified";
}
Library res = new Library();
res.folder = libFolder;
String types = properties.get("types");
if (types == null) {
types = "Contributed";
}
List<String> typesList = new LinkedList<String>();
for (String type : types.split(",")) {
typesList.add(type.trim());
}
UserLibrary res = new UserLibrary();
res.setInstalledFolder(libFolder);
res.setInstalled(true);
res.name = properties.get("name").trim();
res.version = properties.get("version").trim();
res.author = properties.get("author").trim();
res.maintainer = properties.get("maintainer").trim();
res.sentence = properties.get("sentence").trim();
res.paragraph = properties.get("paragraph").trim();
res.url = properties.get("url").trim();
res.website = properties.get("url").trim();
res.category = category.trim();
res.license = license.trim();
res.architectures = archs;
res.isLegacy = false;
res.layout = layout;
res.declaredTypes = typesList;
return res;
}
private static Library createLegacyLibrary(File libFolder) {
// construct an old style library
Library res = new Library();
res.folder = libFolder;
res.layout = LibraryLayout.FLAT;
res.name = libFolder.getName();
res.architectures = Arrays.asList("*");
res.isLegacy = true;
return res;
}
/**
* Returns <b>true</b> if the library declares to support the specified
* architecture (through the "architectures" property field).
*
* @param reqArch
* @return
*/
public boolean supportsArchitecture(String reqArch) {
return architectures.contains(reqArch) || architectures.contains("*");
}
/**
* Returns <b>true</b> if the library declares to support at least one of the
* specified architectures.
*
* @param reqArchs
* A List of architectures to check
* @return
*/
public boolean supportsArchitecture(List<String> reqArchs) {
if (reqArchs.contains("*"))
return true;
for (String reqArch : reqArchs)
if (supportsArchitecture(reqArch))
return true;
return false;
}
public static final Comparator<Library> CASE_INSENSITIVE_ORDER = new Comparator<Library>() {
@Override
public int compare(Library o1, Library o2) {
return o1.getName().compareToIgnoreCase(o2.getName());
}
};
@Override
public String getName() {
return name;
}
public File getFolder() {
return folder;
}
@Override
public List<String> getArchitectures() {
return architectures;
}
@Override
public String getAuthor() {
return author;
}
@Override
public String getParagraph() {
return paragraph;
}
@Override
public String getSentence() {
return sentence;
}
public String getUrl() {
return url;
@Override
public String getWebsite() {
return website;
}
@Override
public String getCategory() {
return category;
}
@Override
public List<String> getTypes() {
return types;
}
public void setTypes(List<String> types) {
this.types = types;
}
@Override
public String getLicense() {
return license;
}
@ -235,44 +221,82 @@ public class Library {
return CATEGORIES;
}
@Override
public void setCategory(String category) {
this.category = category;
}
@Override
public String getVersion() {
return version;
}
@Override
public String getMaintainer() {
return maintainer;
}
@Override
public String getChecksum() {
return null;
}
@Override
public long getSize() {
return 0;
}
@Override
public String getUrl() {
return null;
}
@Override
public String getArchiveFileName() {
return null;
}
@Override
public List<ContributedLibraryReference> getRequires() {
return null;
}
public List<String> getDeclaredTypes() {
return declaredTypes;
}
protected enum LibraryLayout {
FLAT, RECURSIVE
}
protected LibraryLayout layout;
public File getSrcFolder() {
switch (layout) {
case FLAT:
return getInstalledFolder();
case RECURSIVE:
return new File(getInstalledFolder(), "src");
default:
return null; // Keep compiler happy :-(
}
}
public boolean useRecursion() {
return (layout == LibraryLayout.RECURSIVE);
}
public File getSrcFolder() {
switch (layout) {
case FLAT:
return folder;
case RECURSIVE:
return new File(folder, "src");
default:
return null; // Keep compiler happy :-(
}
}
public boolean isLegacy() {
return isLegacy;
}
@Override
public String toString() {
String res = "Library:";
res += " (name=" + name + ")";
res += " (version=" + version + ")";
res += " (author=" + author + ")";
res += " (maintainer=" + maintainer + ")";
res += " (sentence=" + sentence + ")";
res += " (paragraph=" + paragraph + ")";
res += " (url=" + url + ")";
res += " (architectures=" + architectures + ")";
String res = "Library: " + name + "\n";
res += " (version=" + version + ")\n";
res += " (author=" + author + ")\n";
res += " (maintainer=" + maintainer + ")\n";
res += " (sentence=" + sentence + ")\n";
res += " (paragraph=" + paragraph + ")\n";
res += " (url=" + website + ")\n";
res += " (architectures=" + architectures + ")\n";
return res;
}
}

View File

@ -42,6 +42,9 @@ import java.util.regex.*;
* Class that orchestrates preprocessing p5 syntax into straight Java.
*/
public class PdePreprocessor {
private static final String IMPORT_REGEX = "^\\s*#include\\s*[<\"](\\S+)[\">]";
// stores number of built user-defined function prototypes
public int prototypeCount = 0;
@ -94,10 +97,9 @@ public class PdePreprocessor {
}
//String importRegexp = "(?:^|\\s|;)(import\\s+)(\\S+)(\\s*;)";
String importRegexp = "^\\s*#include\\s*[<\"](\\S+)[\">]";
programImports = new ArrayList<String>();
String[][] pieces = PApplet.matchAll(program, importRegexp);
String[][] pieces = PApplet.matchAll(program, IMPORT_REGEX);
if (pieces != null)
for (int i = 0; i < pieces.length; i++)
@ -121,6 +123,19 @@ public class PdePreprocessor {
return headerCount + prototypeCount;
}
public static List<String> findIncludes(String code){
String[][] pieces = PApplet.matchAll(code, IMPORT_REGEX);
ArrayList programImports = new ArrayList<String>();
if (pieces != null)
for (int i = 0; i < pieces.length; i++)
programImports.add(pieces[i][1]); // the package name
return programImports;
}
static String substituteUnicode(String program) {
// check for non-ascii chars (these will be/must be in unicode format)

View File

@ -10,9 +10,9 @@ import java.io.OutputStream;
/**
* Handy process executor, collecting stdout into a given OutputStream
*/
public class ExternalProcessExecutor extends DefaultExecutor {
public class CollectStdOutExecutor extends DefaultExecutor {
public ExternalProcessExecutor(final OutputStream os) {
public CollectStdOutExecutor(final OutputStream stdout) {
this.setStreamHandler(new ExecuteStreamHandler() {
@Override
public void setProcessInputStream(OutputStream outputStream) throws IOException {
@ -27,7 +27,7 @@ public class ExternalProcessExecutor extends DefaultExecutor {
byte[] buf = new byte[4096];
int bytes = -1;
while ((bytes = inputStream.read(buf)) != -1) {
os.write(buf, 0, bytes);
stdout.write(buf, 0, bytes);
}
}

View File

@ -0,0 +1,49 @@
package processing.app.tools;
import org.apache.commons.exec.DefaultExecutor;
import org.apache.commons.exec.ExecuteStreamHandler;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* Handy process executor, collecting stdout and stderr into given OutputStreams
*/
public class CollectStdOutStdErrExecutor extends DefaultExecutor {
public CollectStdOutStdErrExecutor(final OutputStream stdout, final OutputStream stderr) {
this.setStreamHandler(new ExecuteStreamHandler() {
@Override
public void setProcessInputStream(OutputStream outputStream) throws IOException {
}
@Override
public void setProcessErrorStream(InputStream inputStream) throws IOException {
byte[] buf = new byte[4096];
int bytes = -1;
while ((bytes = inputStream.read(buf)) != -1) {
stderr.write(buf, 0, bytes);
}
}
@Override
public void setProcessOutputStream(InputStream inputStream) throws IOException {
byte[] buf = new byte[4096];
int bytes = -1;
while ((bytes = inputStream.read(buf)) != -1) {
stdout.write(buf, 0, bytes);
}
}
@Override
public void start() throws IOException {
}
@Override
public void stop() {
}
});
}
}

View File

@ -0,0 +1,35 @@
package processing.app.tools;
import org.apache.commons.exec.CommandLine;
import processing.app.helpers.OSUtils;
import java.io.File;
public class DoubleQuotedArgumentsOnWindowsCommandLine extends CommandLine {
public DoubleQuotedArgumentsOnWindowsCommandLine(String executable) {
super(executable);
}
public DoubleQuotedArgumentsOnWindowsCommandLine(File executable) {
super(executable);
}
public DoubleQuotedArgumentsOnWindowsCommandLine(CommandLine other) {
super(other);
}
@Override
public CommandLine addArgument(String argument, boolean handleQuoting) {
// Brutal hack to workaround windows command line parsing.
// http://stackoverflow.com/questions/5969724/java-runtime-exec-fails-to-escape-characters-properly
// http://msdn.microsoft.com/en-us/library/a1y7w461.aspx
// http://bugs.sun.com/view_bug.do?bug_id=6468220
// http://bugs.sun.com/view_bug.do?bug_id=6518827
if (argument.contains("\"") && OSUtils.isWindows()) {
argument = argument.replace("\"", "\\\"");
}
return super.addArgument(argument, handleQuoting);
}
}

View File

@ -22,23 +22,21 @@
package processing.app.windows;
import com.sun.jna.Library;
import com.sun.jna.Native;
import org.apache.commons.exec.CommandLine;
import org.apache.commons.exec.Executor;
import processing.app.PreferencesData;
import processing.app.debug.TargetPackage;
import processing.app.legacy.PApplet;
import processing.app.legacy.PConstants;
import processing.app.tools.ExternalProcessExecutor;
import processing.app.tools.CollectStdOutExecutor;
import processing.app.windows.Registry.REGISTRY_ROOT_KEY;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@ -55,7 +53,7 @@ public class Platform extends processing.app.Platform {
"\\arduino.exe \"%1\"";
static final String DOC = "Arduino.Document";
public void init() {
public void init() throws IOException {
super.init();
checkAssociations();
@ -244,7 +242,7 @@ public class Platform extends processing.app.Platform {
// "Access is denied" in both cygwin and the "dos" prompt.
//Runtime.getRuntime().exec("cmd /c " + currentDir + "\\reference\\" +
// referenceFile + ".html");
if (url.startsWith("http://")) {
if (url.startsWith("http")) {
// open dos prompt, give it 'start' command, which will
// open the url properly. start by itself won't work since
// it appears to need cmd
@ -281,36 +279,6 @@ public class Platform extends processing.app.Platform {
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// Code partially thanks to Richard Quirk from:
// http://quirkygba.blogspot.com/2009/11/setting-environment-variables-in-java.html
static WinLibC clib = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
public interface WinLibC extends Library {
//WinLibC INSTANCE = (WinLibC) Native.loadLibrary("msvcrt", WinLibC.class);
//libc = Native.loadLibrary("msvcrt", WinLibC.class);
public int _putenv(String name);
}
public void setenv(String variable, String value) {
//WinLibC clib = WinLibC.INSTANCE;
clib._putenv(variable + "=" + value);
}
public String getenv(String variable) {
return System.getenv(variable);
}
public int unsetenv(String variable) {
//WinLibC clib = WinLibC.INSTANCE;
//clib._putenv(variable + "=");
//return 0;
return clib._putenv(variable + "=");
}
@Override
public String getName() {
return PConstants.platformNames[PConstants.WINDOWS];
@ -318,6 +286,7 @@ public class Platform extends processing.app.Platform {
@Override
public Map<String, Object> resolveDeviceAttachedTo(String serial, Map<String, TargetPackage> packages, String devicesListOutput) {
assert packages != null;
if (devicesListOutput == null) {
return super.resolveDeviceAttachedTo(serial, packages, devicesListOutput);
}
@ -338,7 +307,7 @@ public class Platform extends processing.app.Platform {
@Override
public String preListAllCandidateDevices() {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Executor executor = new ExternalProcessExecutor(baos);
Executor executor = new CollectStdOutExecutor(baos);
try {
String listComPorts = new File(System.getProperty("user.dir"), "hardware/tools/listComPorts.exe").getCanonicalPath();
@ -350,4 +319,24 @@ public class Platform extends processing.app.Platform {
return super.preListAllCandidateDevices();
}
}
@Override
public void fixPrefsFilePermissions(File prefsFile) throws IOException {
//noop
}
public List<File> postInstallScripts(File folder) {
List<File> scripts = new LinkedList<File>();
scripts.add(new File(folder, "post_install.bat"));
return scripts;
}
public void symlink(File something, File somewhere) throws IOException, InterruptedException {
}
public void link(File something, File somewhere) throws IOException, InterruptedException {
}
public void chmod(File file, int mode) throws IOException, InterruptedException {
}
}